2012-03-24 110 views
2

我正在爲一個大學項目工作,我有以下問題: 我在Oracle DB中有兩個表...我需要從表1中選擇那些行,其中不包括在表2 ......但主要的問題是,我需要排除從表2至極行選擇一次...例如:如何只從一個表中減去另一個表中的行

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中有一個「雙胞胎」,它們都被排除在外。

+0

嗨,我可以澄清問題嗎? 您僅在數字和字母上匹配(即,您在Id上不匹配)。 並且表2中的每個條目僅從Table1中排除一個條目(因此對於4 S,Table1中id = 1的行被表2中的id = 3的行排除,但Table1中的id = 4不是? – GregHNZ 2012-03-24 02:40:26

+0

是的,I只看到取消雙胞胎,就像Table1中的id = 1的行被Table2中的id = 3的行取消一樣(Table1中的rowid = 5也被Table2中的rowid = 4取消),但id = 4表1(相同的數字和字母4 S)必須在結果中返回,原因未被Table2中的任何行取消... – slyder07 2012-03-24 03:07:05

+0

因此,如果table2中的id是高於表1中的那個? – 2012-03-25 08:00:06

回答

1

可能最透徹的查詢是這樣的:

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 
; 

,其給出了table1table2「行數」的組「雙胞胎」中的每個記錄。例如,這樣的:

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 

這就是說,如果你知道,沒有(digit, letter)都不能出現比table2一次,可以大大地使用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 
     ) 
; 
+0

謝謝ruakh,這正是我正在尋找的querry。 – slyder07 2012-03-24 03:31:37

+0

@ slyder07:不客氣! – ruakh 2012-03-24 12:02:56

1

將其分成幾部分。

也許你有一個EOR - Exclusive OR。您可能有
(condition1
OR
condition2)
AND NOT
(condition1 AND condition2)

-1

我看不到如何用一個SQL SELECT做你想做的事。

我認爲你需要一個臨時表和幾個語句。

呼叫它tmpResults,與id1id2,匹配來自Table1ididTable2分別哪個。

-- 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; 
相關問題