简体   繁体   中英

How to find missing records from two tables in one query?

I have two tables, items and items_archive which are both missing information due to a faulty stored procedure.

I have a table items_restored that I restored from text backups that contains many items that are not in items or items_archive and I need to end up inserting what items_restored has into items_archive .

I am able to find a one off comparison pretty easily, doing

SELECT ir.id, i_a.id
FROM items_restord as ir
LEFT JOIN items_archive as i_a ON ir.id = i_a.id
WHERE i_a.id IS NULL;

This gives me a list of id's that I have in items_restored that are not in items_archive , however the problem is that some of them MAY be present in items . The same issue happens if I run the above query on items instead of items_archive , I see whats missing but it's very possible the missing id is in items_archive .

I need to run an INSERT eventually and I think if I do it piece meal based on these queries, there's a good chance I'm going to end up inserting duplicate records which I want to avoid.

How can I craft the query to check both items and items_archive id's to compare to my items_restored id's so that I can avoid the duplication?

Edit: I ended up going with union all, which I did right after the LEFT JOIN . Thanks everyone.

You can repeat the LEFT JOIN :

SELECT ir.id  --, i_a.id -- this is always NULL so why select it?
FROM items_restord  ir LEFT JOIN
     items_archive i_a 
     ON ir.id = i_a.id LEFT JOIN
     items i
     ON ir.id = i.id
WHERE i_a.id IS NULL AND i.id IS NULL;

I think NOT EXISTS is a cleaner way to express the logic:

select ir.*
from items_restord ir
where not exists (select 1 from items_archive i_a where ir.id = i_a.id) and
      not exists (select 1 from items i where ir.id = i.id);

I would recommend the merge statement. You'll be able to compare all of the data between those, but set conditions based on matched, no match, etc. which would alleviate some of the issues you denoted. However, merge is only available in SQL Server 2008+ if I recall, so the syntax may not be available since you tagged only SQL.

MERGE INTO items_archive AS Target
USING (
     SELECT ...
     FROM items_restore AS Source (
          ...
     )
)

ON (target.Id = source.Id)
WHEN MATCHED THEN UPDATE SET
     ...
WHEN NOT MATCHED BY TARGET THEN INSERT (
     ...
) VALUES ( 
     ...
)

WHEN NOT MATCHED BY SOURCE THEN DELETE
OUTPUT $action, Inserted.*, Deleted.*;

I did condense code for brevity since I am not sure of specific column names, but you can also couple with an output action to indicate what the query is doing easily. But good way to merge data between tables of like sorts.

You mention finding the missing data, my thought was if a match does not exists it would be created and thrown into the output log.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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