2012-06-15 81 views
1

我有這些表:Oracle SQL - 組合兩個表,但是從一個表中複製?

Table A 
Num Letter 
1 A  
2 B  
3 C  

Table B 
Num Letter 
2 C  
3 D 
4 E 

我想聯盟這兩個表,但我只希望每個號碼出現一次。如果兩個表中出現相同的數字,我希望從表B中取代表A。

Result 
Num Letter 
1 A 
2 C 
3 D 
4 E 

我怎麼能做到這一點?聯合會保持重複,並且相交只會捕捉相同的行 - 無論字母如何,我都認爲行有重複的地方。

回答

0

效率可能不足,但它會產生正確的答案。

select nums.num, coalesce(b.letter, a.letter) 
from 
(select num from b 
union 
select num from a) nums 
left outer join b 
on (b.num = nums.num) 
left outer join a 
on (a.num = nums.num); 
1

試試這個:http://www.sqlfiddle.com/#!4/0b796/1

with a as 
(
    select Num, 'A' as src, Letter 
    from tblA 
    union 
    select Num, 'B' as src, Letter 
    from tblB 
) 
select 

    Num 

    ,case when count(*) > 1 then 
     min(case when src = 'B' then Letter end) 
    else 
     min(Letter) 
    end as Letter 

from a 
group by Num 
order by Num; 

輸出:

| NUM | LETTER | 
---------------- 
| 1 |  A | 
| 2 |  C | 
| 3 |  D | 
| 4 |  E | 
0

或者你可以使用Oracle特定的技術,使代碼更短:http://www.sqlfiddle.com/#!4/0b796/11

with a as 
(
    select Num, 'A' as src, Letter 
    from tblA 
    union 
    select Num, 'B' as src, Letter 
    from tblB 
) 
select Num, min(Letter) keep(dense_rank first order by src desc) as Letter 
from a 
group by Num 
order by Num; 

輸出:

| NUM | LETTER | 
---------------- 
| 1 |  A | 
| 2 |  C | 
| 3 |  D | 
| 4 |  E | 

代碼工作不管min(letter)max(letter),它具有相同的輸出,它給出了相同的輸出。重要的是你使用keep dense_rank。另一個重要的事情是,訂單問題,我們使用order by src desc來保持行時優先源表B。


而真正使其更短,使用keep dense_rank last,並省略desc訂單,asc是默認反正http://www.sqlfiddle.com/#!4/0b796/12

with a as 
(
    select Num, 'A' as src, Letter 
    from tblA 
    union 
    select Num, 'B' as src, Letter 
    from tblB 
) 
select Num, min(Letter) keep(dense_rank last order by src) as Letter 
from a 
group by Num 
order by Num; 

同樣,使用minmax上信不要緊,只要您保持dense_rank獲得優先級/首選行

0

另一種選擇是按如下方式組合UNION和MINUS命令:

SELECT 
    NUM, LETTER 
FROM 
    TABLE B 
UNION 
(SELECT 
     NUM, LETTER 
    FROM 
     TABLE A 
    WHERE 
     NUM IN (SELECT 
        NUM 
       FROM 
        TABLE A 
       MINUS 
       SELECT 
        NUM 
       FROM 
        TABLE B)) 
+0

字母 'B' 必須被排除,這裏是你的代碼的http://www.sqlfiddle。 com /#!4/0b796/13 –

+0

好的一點 - 我誤以爲是rownum。更新了查詢以反映這一點。 –

1

而另一個問題:

SELECT COALESCE(b.num, a.num) num, COALESCE(b.letter, a.letter) letter 
    FROM a FULL JOIN b ON a.num = b.num 
ORDER BY 1; 

與您的數據:

WITH a AS 
(SELECT 1 num, 'A' letter FROM dual 
UNION ALL SELECT 2, 'B' FROM dual 
UNION ALL SELECT 3, 'C' FROM dual), 
b AS 
(SELECT 2 num, 'C' letter FROM dual 
UNION ALL SELECT 3, 'D' FROM dual 
UNION ALL SELECT 4, 'E' FROM dual) 
SELECT COALESCE(b.num, a.num) num, COALESCE(b.letter, a.letter) letter 
    FROM a FULL JOIN b ON a.num = b.num 
ORDER BY 1; 

     NUM L 
---------- - 
     1 A 
     2 C 
     3 D 
     4 E 
+0

+1 FULL JOIN和COALESCE是我第一個[嘗試](http://www.sqlfiddle.com/#!4/0b796/2)。我沒有注意到我沒有使用星號。我錯誤地只放了一個B的列(brainfart),我認爲FULL JOIN排除了A行(Number 1);但它在那裏,我應該在調試或試用代碼時使用星號。下一次將練習星號來查看完整的數據,只有在最終查詢和生產時纔有選擇性的列http://www.sqlfiddle.com/#!4/0b796/23з –

+0

嗯..不能僅在sqlfiddle上使用星號。只有一列具有相同名稱的列時纔會選擇一個列http://www.sqlfiddle.com/#!4/0b796/23,並且必須消除http://www.sqlfiddle.com/#!4/0b796/25中的歧義。無論如何,我不應該懷疑FULL JOIN,因爲我認爲它行爲不端(不包括A的Number 1),因此我很快就制定了[另一種方法](http://stackoverflow.com/questions/11059372/oracle-sql-combining - 兩個 - 表 - 丁取重複-從酮/ 11059539#11059539)。感謝這個答案,這加強了我的想法,即完全連接是這種需求的完美方法 –

0
SELECT A.* 
FROM A 
WHERE A.NUM NOT IN 
    (SELECT A.NUM 
    FROM B 
    WHERE A.NUM=B.NUM 
    AND B.NUM IS NOT NULL 
    AND A.NUM IS NOT NULL 
) 
UNION 
SELECT * FROM B; 
+0

你可以使用union all而不是union來避免額外的區分。 – Ben

相關問題