【问题标题】:Get rows that don't match rows in another table获取与另一个表中的行不匹配的行
【发布时间】:2014-09-19 14:39:09
【问题描述】:

在 SQL 中,我将如何执行反向连接之类的操作?

例如假设我有以下两个表

UsedSlide
    SlideId
    UserId
    SomeOtherValue

LegacySlide
   SlideId
   UserId

如何选择UsedSlideSlideIdUserIdLegacySlide 任何行中的值都不匹配的所有行?

请注意,我专门做了两件事,因为否则我知道我可以使用 NOT IN 和子选择。

奖励:在我的场景中,数据集很小,但如果它很大怎么办?如何最有效地做到这一点?

【问题讨论】:

    标签: sql


    【解决方案1】:

    您可以使用not exists 运算符:

    SELECT *
    FROM   UsedSlide u
    WHERE  NOT EXISTS (SELECT *
                       FROM   LegacySlide l
                       WHERE  u.SlideId = l.SlideId AND u.UserId = l.UserId)
    

    【讨论】:

    • 是的,我就是这么想的(SELECT 1 也可能更好)。但是,在大型数据集上这种预制件不会很可怕吗?
    • 累积。对于他的“奖励问题”,NOT EXISTS 也是最有效的方法(具有适当的索引)。 sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-join
    • @GeorgeMauer: 也可以使用SELECT 1,但它并不比SELECT * 更有效。
    • 哦,好吧,我假设你没有投影所有行,但我猜优化器会处理它
    【解决方案2】:

    可以使用左连接

      SELECT * from
      UsedSlide US
      LEFT JOIN LegacySlide LS
      ON US.SlideId = LS.SlideId
      and US.UserId = LS.UserId
      WHERE LS.SlideId is NULL
      AND LS.UserId is NULL
    

    【讨论】:

    • 这很有趣......关于这个与NOT EXISTS 的性能有什么想法吗?另外,WHERE 子句不应该测试ls,而不是us
    • 在 SQL Server 中,使用 NOT EXISTS 时,大量数据的性能会有所下降。是的,你是对的,需要检查 LS,我会更新
    • @georg:在对另一个答案的评论中,我提供了一个链接到一篇文章的链接,该文章添加了这个主题,它解释了为什么 Not Exists 可以比其他方法更有效并且空值没有问题(喜欢加入)。
    【解决方案3】:

    使用 EXCEPT 运算符:

    我测试过的一些示例代码:

    CREATE TABLE #UsedSlide (SlideId INT NOT NULL, UserId INT NOT NULL, SomeOtherValue VARCHAR(10) NOT NULL)
    CREATE TABLE #LegacySlide (SlideId INT NOT NULL, UserId INT NOT NULL)
    
    INSERT INTO #UsedSlide(SlideId, UserId, SomeOtherValue)
    VALUES
    (1, 35, 'testing123'),
    (2, 39, 'testingabc'),
    (3, 24, 'testingxyz')
    
    INSERT INTO #LegacySlide( SlideId, UserId )
    VALUES  (1, 35),
            (2, 39)
    
    SELECT SlideId, UserId
    FROM #UsedSlide
    EXCEPT
    SELECT SlideId, UserId
    FROM #LegacySlide
    

    这会产生以下结果集:

    SlideId UserId
    ------- ------
    3       24
    

    注意:EXCEPT 中的语句顺序在这里很重要。如果您将最后一条语句运行为:

    SELECT SlideId, UserId
    FROM #LegacySlide
    EXCEPT
    SELECT SlideId, UserId
    FROM #UsedSlide
    

    ...不会产生预期的效果。这基本上是对集合的操作:找到不在元组集合中的“元组”。

    EXCEPT 的配套运算符是 INTERSECT - 查找两个集合之间的共同元组。两者都是非常有用的运算符。

    顺便说一句,我认为Oracle有一个MINUS运算符,大致相当于EXCEPT(有人可以验证并找到链接吗?)

    【讨论】:

    • 这可以用于从UsedSlide 中选择所有 列,还是我们需要加入?
    • 需要再次加入原始表:SELECT u.SlideId, u.UserId, SomeOtherValue FROM #UsedSlide u JOIN (SELECT SlideId, UserId FROM # UsedSlide EXCEPT SELECT SlideId, UserId FROM #LegacySlide ) m ON u.SlideId = m.SlideId AND u.UserId = m.UserId
    • @Rajesh,您的方法非常可行,但由于 IS NULL 检查,大型数据集的性能可能会受到影响。这是一篇描述 IS NULL 性能不佳的好帖子:blogs.lessthandot.com/index.php/datamgmt/datadesign/…
    猜你喜欢
    • 2012-12-20
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多