Domanda

Consider the following schema:

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

And the following query:

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

In SQL Fiddle (SQL Server 2008) I get the following result:

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

But replacing the INNER JOIN of the subquery by CROSS APPLY fixes the issue:

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

My questions are:

1) Why the first query fail?

2) Why the second query doesn't fail?

3) CROSS APPLY is specific to SQL Server. Which would be the SQL Standard solution to this problem?

Important note: Don't try to understand the logic behind TableA, ..., TableD. They're just an abstraction to a more complex query (which is awful to read). I think you'll get the idea of the issue.

È stato utile?

Soluzione

Correlated subqueries are not allowed in from clauses. That is why the inner join version does not work. I don't actually know the history of this. One problem is that you could get cycles in the dependencies, which while not hard to detect, make the query impossible to process.

Your query with cross apply is one case where cross apply fits well. However, I don't know how well it executes on large data.

Here is an attempt to rewrite it in standard 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top