简体   繁体   English

SQL - 检查表中是否有新行?

[英]SQL - Check table for new rows?

I have two tables, for example:我有两个表,例如:

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

Table A is my source table and B is the destination table.表 A 是我的源表,B 是目标表。 Now I need a query which finds all the different (additional) rows in table A so table B can be updated with those rows.现在我需要一个查询来查找表 A 中所有不同(附加)的行,以便可以用这些行更新表 B。 So I need a query which finds me the following rows from table A:所以我需要一个查询来从表 A 中找到以下行:

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

What is a good approach for such a query?这种查询的好方法是什么? It should be as efficient as possible (avoid too many joins).它应该尽可能高效(避免太多连接)。 Thanks for any help!谢谢你的帮助!

I would use a NOT EXISTS structure.我会使用 NOT EXISTS 结构。

SELECT Name, Color
FROM TableA
WHERE NOT EXISTS (
SELECT 1 FROM TableB
WHERE TableA.Name = TableB.Name 
AND TableA.Color = TableB.Color)
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
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

In SQL Server 2008, you can use the EXCEPT operator, which is used like a UNION but returns everything from the first query, except where it is also in the second:在 SQL Server 2008 中,您可以使用EXCEPT运算符,它的用法类似于UNION但返回第一个查询中的所有内容,除了它也在第二个查询中:

SELECT * FROM TABLEA EXCEPT SELECT * FROM TABLEB

I understand that Oracle has a MINUS operator that does the same thing.我知道 Oracle 有一个MINUS运算符可以做同样的事情。

You can use the EXCEPT operator, which is the opposite of UNION.您可以使用 EXCEPT 运算符,它与 UNION 相反。 In Oracle, the equivalent is MINUS.在 Oracle 中,相当于 MINUS。

SELECT * FROM TABLE_A
EXCEPT
SELECT * FROM TABLE_B

I usually add a column "updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP", and I use its value to check when a new row is inserted or an existing one is modified.我通常添加一列“updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP”,我使用它的值来检查何时插入新行或修改现有行。

In an application I developed I needed to solve a problem similar to yours, so I saved somewhere the MAX(updated) of B, and then with a query I identified all the rows where A.updated>B.updated, and the result are all new+modified rows.在我开发的一个应用程序中,我需要解决一个与您类似的问题,所以我将 B 的 MAX(updated) 保存在某处,然后通过查询识别出 A.updated>B.updated 的所有行,结果是所有新的+修改的行。

Since the field default value is CURRENT_TIMESTAMP and it auto-updates "ON UPDATE" you never have to explicitly set its value.由于字段默认值为 CURRENT_TIMESTAMP 并且它会自动更新“ON UPDATE”,因此您无需明确设置其值。

A NOT EXISTS subquery should resolve to an outer join: NOT EXISTS子查询应该解析为外连接:

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

Or you could just use an outer join directly:或者您可以直接使用外连接:

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

They should be equally performant;它们的性能应该相同; it's a question of which you feel is more intuitive.这是一个你觉得更直观的问题。

There are many correct answers up already, but I want to bring up a philosophical point:已经有很多正确的答案,但我想提出一个哲学观点:

Is this database schema really viable in a production environment inside a single schema?这个数据库模式在单个模式内的生产环境中真的可行吗?

Does it really make sense to have two tables containing data, and then writing a query to compare one to the other?有两个包含数据的表,然后编写一个查询来比较一个和另一个真的有意义吗? I think it would make sense to have just a single table, and perhaps put in a date identifier to find records added after a certain point.我认为只有一个表是有意义的,也许可以输入一个日期标识符来查找在某个点之后添加的记录。

The only situation I can think of where you'd want to do this is where you have two separate databases and you want to "synchronize" them, or when you would want to find differences between the two, say, comparing a backup and production.我能想到的唯一情况是你有两个独立的数据库并且你想要“同步”它们,或者当你想要找到两者之间的差异时,比如比较备份和生产.

In Oracle you would probably use:在 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);

If your table has a primary key (do you really have tables without one?) like NAME, and you would like to INSERT or UPDATE depending on the existence of the record in table B, you would use:如果你的表有一个主键(你真的有没有一个的表吗?)比如 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; 

I take it that SQL Server also has a MERGE statement or similar.我认为 SQL Server 也有一个 MERGE 语句或类似的语句。

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

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
    select 
        name, 
        color
    from 
        tableA 
    where 
        concat(name, '|',color)  
        not in 
        (
            select 
                concat(name, '|',color) 
            from 
                tableB
        )-- not in 

Working coy can be found at db fiddle工作腼腆可以在db fiddle找到

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM