[英]How to substract rows from one table from another only once
我正在为一个大学项目工作,我有以下问题:我在Oracle DB中有2个表...我需要从table1中选择那些未包含在table2中的行...但是主要问题是我需要排除一次选择了table2的行...例如:
Table1 Table2 ResultTable
id | Number | Letter id | Number | Letter id | Number | Letter
_____________________ _____________________ _____________________
1 4 S 1 6 G 2 2 P
2 2 P 2 8 B 3 5 B
3 5 B 3 4 S 4 4 S
4 4 S 4 1 A 6 2 P
5 1 A 5 1 H
6 2 P 6 2 X
因此,从表上看,如果表1中的一行在表2中具有“双胞胎”,则它们都将被排除。
分成几部分。
也许您有一个EOR-异或。
所以你可能有
(condition1
OR
condition2)
AND NOT
(condition1 AND condition2)(condition1
。
OR
condition2)
AND NOT
(condition1 AND condition2)
也许最彻底的查询是这样的:
SELECT table1.id,
table1.digit,
table1.letter
FROM ( SELECT id,
digit,
letter,
ROW_NUMBER() OVER (PARTITION BY digit, letter ORDER BY id) rn
FROM table1
) table1
LEFT
JOIN ( SELECT id,
digit,
letter,
ROW_NUMBER() OVER (PARTITION BY digit, letter ORDER BY id) rn
FROM table2
) table2
ON table2.digit = table1.digit
AND table2.letter = table1.letter
AND table2.rn = table1.rn
WHERE table2.id IS NULL
ORDER
BY table1.id
;
它为table2
table1
和table2
的每个记录在其“双胞胎”组中提供一个“行号”。 例如,这:
SELECT id,
digit,
letter,
ROW_NUMBER() OVER (PARTITION BY digit, letter ORDER BY id) rn
FROM table1
ORDER
BY table1.id
;
返回此:
ID DIGIT LETT RN
---------- ---------- ---- ----------
1 4 S 1
2 2 P 1
3 5 B 1
4 4 S 2 -- second row with 4 S
5 1 A 1
6 2 P 2 -- second row with 2 P
就是说,如果您知道在table2
中没有(digit, letter)
可以出现多次,则可以使用EXISTS
而不是ROW_NUMBER()
来大大简化此操作:
SELECT id,
digit,
letter
FROM table1 table1a
WHERE EXISTS
( SELECT 1
FROM table1
WHERE digit = table1a.digit
AND letter = table1a.letter
AND id < table1a.id
)
OR NOT EXISTS
( SELECT 1
FROM table2
WHERE digit = table1a.digit
AND letter = table1a.letter
)
;
使用Oracle MINUS关键字,它完全可以满足您的要求。 有关更多详细信息,请参见http://oreilly.com/catalog/mastorasql/chapter/ch07.html 。
我看不到如何使用一个SQL SELECT来完成所需的操作。
我认为您需要一个临时表和一些语句。
将其tmpResults
,其id1
和id2
分别与Table1
的id
和Table2
中的id
匹配。
-- get matched rows - this is too many, we'll delete some later.
INSERT INTO tmpResults (id1, id2)
SELECT Table1.id id1, Table2.id id2
FROM Table1 INNER JOIN Table2
ON Table1.Number = Table2.Number AND Table1.Letter = Table2.Letter;
-- Delete where Table1 has matched more than 1 row
DELETE tmpResults
WHERE rowid IN
(SELECT tmpResults.RowId
FROM tmpResults
INNER JOIN
(SELECT id1, MAX(id2) id2m FROM tmpResults GROUP BY id1 HAVING count(*) > 1) m1
ON tmpResults.id1 = m1.id1 AND tmpResults.id2 = m1.id2m );
-- Delete where Table2 has matched more than 1 row
DELETE tmpResults
WHERE rowid IN
(SELECT tmpResults.RowId
FROM tmpResults
INNER JOIN
(SELECT MAX(id1) id1m, id2 FROM tmpResults GROUP BY id2 HAVING count(*) >1) m2
ON tmpResults.id1 = m2.id1m AND tmpResults.id2 = m2.id2 );
-- now tmpResults should have unique matches only, so we want Table1 where there is no match
SELECT Table1.*
FROM Table1
LEFT JOIN tmpResults
ON table1.id = tmpResults.id1
WHERE tmpResults.id2 IS NULL;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.