查询嵌套查询结果中的两列

Posted

技术标签:

【中文标题】查询嵌套查询结果中的两列【英文标题】:Query where two columns are in the result of nested query 【发布时间】:2011-01-26 01:19:44 【问题描述】:

我正在编写这样的查询:

select * from myTable where X in (select X from Y) and XX in (select X from Y)

X 和 XX 列的值必须在同一查询的结果中:select X from Y

我认为这个查询被调用了两次,所以它毫无意义。还有其他选择我可以更有效地编写此查询吗?也许是临时表?

【问题讨论】:

【参考方案1】:

实际上没有,鉴于 myTable.X 和 myTable.YY 匹配的 X 可能不在同一行,因此没有更聪明的方法来编写此代码(无需访问 Y 两次)。

作为替代,查询的 EXISTS 形式是

select *
from myTable A
where exists (select * from Y where A.X = Y.X)
  and exists (select * from Y where A.XX = Y.X)

如果 Y 包含 X 值 1,2,3,4,5x.x = 2x.xx = 4,则它们都存在(在 Y 中的不同记录上)并且 myTable 中的记录应显示在输出中。

编辑:这个答案之前You could rewrite this using _EXISTS_ clauses which will work faster than _IN_。正如 Martin 所指出的,这不是真的(对于 SQL Server 2005 及更高版本当然不是)。查看链接

http://explainextended.com/2009/06/16/in-vs-join-vs-exists/ http://sqlinthewild.co.za/index.php/2009/08/17/exists-vs-in/

【讨论】:

+1,但存在不一定会更快 - 我的简单测试为两种方法提供了完全相同的查询计划。查询优化器非常聪明,在“优化”你的 sql 时检查计划总是值得的。 +1 在同意之前我不得不离线尝试其他几个,但这是最有效的...... 每个人都有过糟糕的日子,不要把它放在心上:-)。我会赞成中和这一点,因为您的回答显然是正确的(尽管我的回答对原始问题更好:-) 在我的错误中,我投了反对票。亚历克斯礼貌地提醒我我的理解是不正确的——你称我为白痴(直接引用,在我威胁要提醒模组后你已经编辑了评论),并告诉我立即删除它。现在你觉得有必要贴上我的名字来表明误解,并要求扭转局面。是的,伙计,我会马上解决的。当我们这样做的时候,reversing the downvote on my answer earlier 呢?如果你不喜欢它,不要对别人这样做。 inexists 做get treated the same in SQL Server AFAIK。【参考方案2】:

尝试通过仅引用一次Y 来编写此查询可能不会特别有效。但是,鉴于您使用的是 SQL Server 2008,因此可以使用多种变体:

Select ...
From MyTable As T
Where Exists    (
                Select 1
                From Y
                Where Y.X = T.X
                Intersect
                Select 1
                From Y
                Where Y.X = T.XX
                )

加法

实际上,我可以想到一种方法,无需多次使用Y 就可以做到这一点(没有提到多次使用MyTable)。然而,这更多是出于学术原因,因为我认为使用我的第一个解决方案可能会表现得更好:

Select ...
From MyTable As T
Where Exists    (
                Select 1
                From Y
                Where Exists( 
                            Select 1 
                            From MyTable1 As T1 
                            Where T1.X = Y.X 
                            Intersect
                            Select 1 
                            From MyTable1 As T2 
                            Where T2.XX = Y.X
                            )
                    And Y.X In(T.X, T.XX)
                )

【讨论】:

【参考方案3】:
WITH
   w_tmp AS(
      SELECT x
        FROM y
   )
SELECT * 
  FROM myTable
 WHERE x IN (SELECT x FROM w_tmp)
   AND xx IN (SELECT x FROM w_tmp)

(我已在 Oracle 文档中阅读过此内容,但我认为 MS 也可以进行此优化) 这样优化器可以确定您正在执行相同的查询,并且可以创建临时表来兑现结果(但仍然由优化器决定是否值得。对于微小的查询,创建临时表的开销可能太高)。

另外(实际上这对我来说更重要),当子查询是 50 行时,human 更容易看到,在两种情况下都使用相同的东西。很像将长函数分解为子例程

Docs on MSDN

【讨论】:

这可能会让您感到惊讶,但 CTE w_tmp 是 evaluated twice,是的。检查查询计划。它没有存储在一些临时内存中。 @cyberkiwi:由优化器决定是否值得。对于微小的查询,创建临时表的开销可能太高。感谢您的评论,我会更新帖子以澄清这一点。 Oracle 有实现 CTE 的提示(Oracle 称之为“子查询分解”),但除此之外,使用 CTE 并没有性能优势。 @OMG Ponies:它可以在没有提示的情况下做到这一点。请参阅 asktom.oracle.com/pls/asktom/… 的 Tom Kyte 的第二个答案。或者这篇文章中的例子oracle-developer.net/display.php?id=212 Tom 没有澄清版本 - 请参阅:jonathanlewis.wordpress.com/2007/07/26/subquery-factoring-2【参考方案4】:

不确定问题是什么,但不是简单的 JOIN 答案吗?

SELECT t.* 
FROM myTable 
JOIN Y y1 ON y1.X = myTable.X
JOIN Y y2 ON y2.X = myTable.XX

SELECT t.*
FROM myTable, Y y1, Y y2
WHERE y1.X = myTable.X AND y2.X = myTable.XX

添加:如果强烈需要消除对 Y 的第二次查询,让我们颠倒逻辑:

;WITH A(X)
AS (
  -- this will select all values that can be found in Y and myTable X and XX fields.
  SELECT Y.X -- if there are a lot of dups, add DISTINCT
  FROM Y, myTable
  WHERE Y.X IN (myTable.X, myTableXX)
)
-- now join back to the orignal table and filter.
SELECT t.* 
FROM myTable
-- similar to what has been mentioned before 
WHERE EXISTS(SELECT TOP 1 * from A where A.X = myTable.X)
      AND EXISTS(SELECT TOP 1 * from A where A.X = myTable.XX)

如果你不喜欢 WITH,你可以使用 SELECT INTO 子句创建内存表。

【讨论】:

问题是:完全相同的查询select X from Y被执行了两次 您不信任 SQL Server 缓存和优化策略? 添加了另一种方式。奇怪的一个。

以上是关于查询嵌套查询结果中的两列的主要内容,如果未能解决你的问题,请参考以下文章

查询结果作为嵌套查询中的列名

嵌套查询与连接查询的区别是啥

mybatis的嵌套查询与嵌套结果查询的不同

如果嵌套查询在 SQL Server 中是不是有结果,如何返回是或否?

Mybatis 的嵌套查询与嵌套结果的区别

Mybatis 的嵌套查询与嵌套结果的区别