【问题标题】:SQL - Check table for new rows?SQL - 检查表是否有新行?
【发布时间】:2009-06-24 14:03:53
【问题描述】:

我有两张表,例如:

Table A                                  Table B
=======                                  =======

Name         | Color                     Name         | Color
----------------------                   ----------------------
Mickey Mouse | red                       Mickey Mouse | red
Donald Duck  | green                     Donald Duck  | blue
Donald Duck  | blue                      Minnie       | red
Goofy        | black
Minnie       | red

表 A 是我的源表,B 是目标表。现在我需要一个查询来查找表 A 中的所有不同(附加)行,以便可以使用这些行更新表 B。 所以我需要一个查询,它可以从表 A 中找到以下行:

Name         | Color  
----------------------
Donald Duck  | green  
Goofy        | black

这样的查询有什么好的方法?它应该尽可能高效(避免过多的连接)。 感谢您的帮助!

【问题讨论】:

  • 这是什么数据库引擎,你在做什么?例如,如果您的意图是以某种方式复制数据,则通常有更好的方法,具体取决于所使用的引擎。
  • 这是一个来自现实生活问题的简化示例,其中表 A 和 B 显然不是那么简单。特别是表 B 不包含与表 A 完全相同的 1:1 列。

标签: sql


【解决方案1】:

我会使用 NOT EXISTS 结构。

SELECT Name, Color
FROM TableA
WHERE NOT EXISTS (
SELECT 1 FROM TableB
WHERE TableA.Name = TableB.Name 
AND TableA.Color = TableB.Color)

【讨论】:

  • NOT EXISTS 使用相关子查询,因此在较大的数据集上它比“NOT IN”快得多。
  • +1 以提高贾斯汀答案的可读性;但是,贾斯汀的可能更快,恕我直言更好。
  • 非常感谢!这正是我所需要的!
【解决方案2】:
SELECT a.Name, a.Color
FROM a LEFT OUTER JOIN b ON (a.Name = b.Name AND a.Color = b.Color)
WHERE b.Name IS NULL AND b.Color IS NULL

【讨论】:

  • 为什么要测试名称和颜色都为 NULL?当然测试其中之一就足够了。
【解决方案3】:
Select A.Name, A.Color
From A left join B on A.Name = B.Name and A.Color = B.Color
Where B.Name is null

【讨论】:

    【解决方案4】:

    您可以使用与 UNION 相反的 EXCEPT 运算符。在 Oracle 中,等价于 MINUS。

    SELECT * FROM TABLE_A
    EXCEPT
    SELECT * FROM TABLE_B
    

    【讨论】:

      【解决方案5】:

      在 SQL Server 2008 中,您可以使用 EXCEPT 运算符,它的用法类似于 UNION,但会返回第一个查询中的所有内容,除了第二个查询中的位置:

      SELECT * FROM TABLEA EXCEPT SELECT * FROM TABLEB
      

      我了解 Oracle 有一个 MINUS 运算符可以做同样的事情。

      【讨论】:

        【解决方案6】:

        我通常会添加一列“updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP”,并使用它的值来检查何时插入新行或修改现有行。

        在我开发的应用程序中,我需要解决与您类似的问题,因此我将 B 的 MAX(updated) 保存在某处,然后通过查询我确定了 A.updated>B.updated 的所有行,并且结果都是新的+修改的行。

        由于字段默认值为 CURRENT_TIMESTAMP 并且它会自动更新“ON UPDATE”,因此您无需显式设置其值。

        【讨论】:

          【解决方案7】:

          NOT EXISTS 子查询应解析为外连接:

          SELECT Name, Color
          FROM TableA
          WHERE NOT EXISTS (
            SELECT 1
            FROM TableB
            WHERE TableA.Color = TableB.Color
            AND   TableA.Name  = TableB.Name
          )
          

          或者你可以直接使用外连接:

          SELECT TableA.Name, TableA.Color
          FROM TableA
          LEFT OUTER JOIN TableB
            ON  TableA.Name  = TableB.Name
            AND TableA.Color = TableB.Color
          WHERE TableB.Name IS NULL
          

          它们应该具有同样的性能;这是一个你觉得更直观的问题。

          【讨论】:

            【解决方案8】:

            在 Oracle 中,您可能会使用:

            MERGE INTO b USING
              (SELECT name, color 
                 FROM a) src 
             ON (src.name = b.name AND color = src.color)
             WHEN NOT MATCHED THEN 
                INSERT (name, color)
                VALUES (src.name, src.color);
            

            如果你的表有一个主键(你真的有没有主键的表吗?)比如 NAME,并且你想根据表 B 中记录的存在来插入或更新,你会使用:

            MERGE INTO b USING 
              (SELECT name, color 
                 FROM a) src 
              ON (src.name = b.name) 
              WHEN NOT MATCHED THEN 
                INSERT (name, color)
                VALUES (src.name, src.color) 
              WHEN MATCHED THEN 
                UPDATE 
                SET color = src.color; 
            

            我认为 SQL Server 也有 MERGE 语句或类似语句。

            【讨论】:

              【解决方案9】:

              已经有很多正确答案了,但我想提出一个哲学观点:

              这种数据库模式在单一模式内的生产环境中真的可行吗?

              拥有两个包含数据的表,然后编写一个查询来比较另一个表真的有意义吗?我认为只有一个表是有意义的,并且可能会放入一个日期标识符来查找在某个时间点之后添加的记录。

              我能想到的唯一情况是你有两个独立的数据库并且你想“同步”它们,或者你想找到两者之间的差异,比如比较一个备份和生产。

              【讨论】:

                【解决方案10】:

                SELECT TableA.Name, TableA.Color FROM TableA WHERE TableA.Name + TableA.Color NOT IN (SELECT TableB.Name + TableB.Color FROM TableB)

                【讨论】:

                  【解决方案11】:
                  INSERT INTO B 
                  SELECT a.Name, a.Color
                  FROM A a
                  LEFT JOIN B b ON a.Name = b.Name AND a.Color = b.Color
                  WHERE b.Color IS NULL AND b.Name IS NULL
                  

                  【讨论】:

                    【解决方案12】:
                        select 
                            name, 
                            color
                        from 
                            tableA 
                        where 
                            concat(name, '|',color)  
                            not in 
                            (
                                select 
                                    concat(name, '|',color) 
                                from 
                                    tableB
                            )-- not in 
                    

                    可以在db fiddle找到工作腼腆的人

                    【讨论】:

                      猜你喜欢
                      • 2021-10-27
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-10-02
                      • 2011-07-21
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多