繁体   English   中英

如何只从一个表中的表中减去行

[英]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 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

就是说,如果您知道在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 ,其id1id2分别与Table1idTable2中的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.

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