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

但是用CROSS APPLY替换子查询的INNER JOIN可以解决问题:

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)为什么第二个查询没有失败?

3) CROSS APPLY特定于 SQL Server。哪一个是这个问题的 SQL 标准解决方案?

重要提示:不要试图理解 TableA、...、TableD 背后的逻辑。它们只是对更复杂查询的抽象(读起来很糟糕)。我想你会明白这个问题的。

4

1 回答 1

3

from子句中不允许使用相关子查询。这就是inner join版本不起作用的原因。我其实不知道这件事的来历。一个问题是您可能会在依赖项中获得循环,这虽然不难检测,但会使查询无法处理。

您的查询是非常适合cross apply的一种情况。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 回答