2

次のスキーマを検討してください。

create table TableA (A1 int)
create table TableB (B1 int, B2 int)
create table TableC (C1 int, C2 int)
create table TableD (D1 int)

そして、次のクエリ:

SELECT * 
FROM TableA a
INNER JOIN TableB b ON b.B1=a.A1
INNER JOIN (SELECT TOP 1 * 
            FROM TableC c
            WHERE c.C1=b.B1 ORDER BY c.C2) foo ON foo.C1=a.A1
INNER JOIN TableD d ON d.D1=foo.C1

SQL Fiddle (SQL Server 2008) では、次の結果が得られます。

The multi-part identifier "b.B1" could not be bound.: SELECT * FROM TableA a INNER JOIN TableB b ON b.B1=a.A1 INNER JOIN (SELECT TOP 1 * FROM TableC c WHERE c.C1=b.B1 ORDER BY c.C2) foo ON foo.C1=a.A1 INNER JOIN TableD d ON d.D1=foo.C1

ただし、サブクエリのINNER JOINをCROSS APPLYに置き換えると、問題が修正されます。

SELECT * 
FROM TableA a
INNER JOIN TableB b ON b.B1=a.A1
CROSS APPLY (SELECT TOP 1 * 
            FROM TableC c
            WHERE c.C1=b.B1 AND c.C1=a.A1 ORDER BY c.C2) foo
INNER JOIN TableD d ON d.D1=foo.C1

私の質問は次のとおりです。

1) 最初のクエリが失敗するのはなぜですか?

2) 2 番目のクエリが失敗しないのはなぜですか?

3) CROSS APPLYは SQL Server に固有です。この問題に対する SQL 標準ソリューションはどれですか?

重要な注意: TableA、...、TableD の背後にあるロジックを理解しようとしないでください。それらは、より複雑なクエリの単なる抽象化です (これは読みにくいです)。問題の趣旨はお分かりいただけると思います。

4

1 に答える 1

3

相関サブクエリはfrom句では許可されていません。そのため、inner joinバージョンが機能しません。これの歴史は実は知りません。1 つの問題は、依存関係にサイクルが発生する可能性があることです。検出は難しくありませんが、クエリを処理できなくなります。

あなたのクエリは、うまく適合するcross apply1つのケースです。cross applyただし、大規模なデータでどの程度実行されるかはわかりません。

これを標準 SQL で書き直してみましょう。

SELECT * 
FROM TableA a
INNER JOIN TableB b ON b.B1=a.A1
INNER JOIN (select *
            from (select c.*, row_number() over (partition by c1 order by c2) 
                  FROM TableC c
                 ) c
            where seqnum = 1 and foo.C1=a.A1 and c.C1=b.B1
           ) foo
INNER JOIN TableD d ON d.D1=foo.C1
于 2013-02-02T00:32:27.250 に答える