同一张表的相关子查询,只有一个别名

Nig*_*loo 2 subquery sybase-sql-anywhere

我有这样的查询

SELECT *
FROM my_table
WHERE ... AND id IN (SELECT t2.id
                     FROM my_table t2
                     WHERE id = t2.id AND ... );
Run Code Online (Sandbox Code Playgroud)

我知道在这个例子中我可以组合这两个WHERE子句并且不使用子查询,但这不是重点。

此查询在我使用的 DBMS(SQL Anywhere 16)上完美运行,但我想知道id在子查询中my_table.id从主查询引用的事实是否是标准行为,或者我是否只是幸运。

链接或参考 RFC 或任何官方文件表示赞赏:)

ype*_*eᵀᴹ 5

不,这是错误的。标准行为是在WHERE id = ...子查询中id引用范围内最近的表。那就是t2my_table仅当t2没有id列时,它才会在外部查询中引用。

不过你很幸运,因为WHERE id = t2.id- 被翻译为WHERE t2.id = t2.id实际上并不需要,因为你使用了WHERE id IN (subquery). 如果你有一个EXISTS 版本,它不会像你预期的那样工作。

因此,编写查询的正确方法要么是所有列引用的前缀:

SELECT t1.*
FROM my_table AS t1
WHERE ... AND t1.id IN 
              (SELECT t2.id
               FROM my_table t2
               WHERE --- t1.id = t2.id AND  -- remove, we don't need this 
               ... );
Run Code Online (Sandbox Code Playgroud)

或者只在需要时非常小心和前缀:

SELECT *
FROM my_table AS t1
WHERE ... AND id IN 
              (SELECT id
               FROM my_table t2
               WHERE --- id = t2.id AND  -- remove, we still don't need this 
                 ... );
Run Code Online (Sandbox Code Playgroud)

我仍然更喜欢EXISTS此类查询的版本:

SELECT t1.*
FROM my_table AS t1
WHERE ... AND EXISTS
              (SELECT *
               FROM my_table t2
               WHERE t1.id = t2.id AND  -- we do need "t1". here
               ... );
Run Code Online (Sandbox Code Playgroud)

或者(如果你总是很小心的话):

SELECT *
FROM my_table AS t1
WHERE ... AND EXISTS
              (SELECT *
               FROM my_table t2
               WHERE t1.id = id AND    -- we need only the "t1". here
                                       -- the second ref, = id is translated
                                       -- to:   = t2.id
               ... );
Run Code Online (Sandbox Code Playgroud)