2016-03-01 44 views
1

我有兩個服務提供商表providersproviders_cleanproviders包含數以千計的提供者格式非常差的數據,providers_clean只有少數提供者仍然存在於'髒'表中。從兩個表中選擇行並排除這兩個表中存在的主鍵

我希望系統使用這些數據在用戶'清理'數據時保持正常運行,所以我希望能夠選擇所有已經'清理'的行和那些行仍然是「髒」,同時排除與「乾淨」相同的「髒」結果。

我如何可以選擇所有供應商從providers_clean表全部由providers表中的供應商合併,排除已經被「清理」的那些

我已經試過:

SELECT * FROM providers WHERE NOT EXISTS (SELECT * FROM providers_clean WHERE providers_clean.id = providers.id) 

這給我所有來自providers的'髒'結果不包括'乾淨'的結果,但我怎樣才能重寫查詢以合併所有'乾淨'的結果從providers_clean

這裏是我想要做的可視化表示:

Clean Table 

+----+-------------------+ 
| ID |  Name  | 
+----+-------------------+ 
| 1 | Clean Provider 1 | 
| 4 | Clean Provider 4 | 
| 5 | Clean Provider 5 | 
+----+-------------------+ 


Dirty Table 
+----+------------------+ 
| ID |  Name  | 
+----+------------------+ 
| 1 | Dirty Provider 1 | 
| 2 | Dirty Provider 2 | 
| 3 | Dirty Provider 3 | 
| 4 | Dirty Provider 4 | 
| 5 | Dirty Provider 5 | 
+----+------------------+ 


Desired Result 

+----+------------------+ 
| ID |  Name  | 
+----+------------------+ 
| 1 | Clean Provider 1 | 
| 2 | Dirty Provider 2 | 
| 3 | Dirty Provider 3 | 
| 4 | Clean Provider 4 | 
| 5 | Clean Provider 5 | 
+----+------------------+ 

感謝

UPDATE

這是工作,但是,有沒有寫一個更有效的方法這個查詢?

SELECT providers.id AS id, 
CASE 
    WHEN 
    providers_clean.id IS NOT NULL 
    THEN 
    providers_clean.provider_name 
    ELSE 
    providers.provider_name 
END AS pname, 

CASE 
    WHEN 
    providers_clean.id IS NOT NULL 
    THEN 
    providers_clean.phone 
    ELSE 
    providers.phone 
END AS pphone, 

CASE 
    WHEN 
    providers_clean.id IS NOT NULL 
    THEN 
    providers_clean.website 
    ELSE 
    providers.website 
END AS pwebsite 

FROM providers 
    LEFT JOIN providers_clean ON providers_clean.id = providers.id 
ORDER BY providers.id asc 
+0

這是我的查詢基本上一樣。 'COALESCE'提供更簡潔的語法來代替'CASE'表達式。我懷疑它可以比這更有效率:它只是一個簡單的'LEFT JOIN'操作。 –

+0

但我不想爲ID以外的任何字段使用'COALESCE'。換句話說,即使在'clean'表中名稱,電話,網站都是'NULL',我希望結果爲NULL,而不是'dirty'表上的值。那是我遇到問題的地方。 – WheatBeak

+0

好吧,我現在看到.... –

回答

1

你需要做的髒外連接到清潔(因爲髒了所有行清理了,但不是反之亦然)

SELECT dirty.id AS id, 
CASE 
    WHEN clean.id IS NOT NULL THEN clean.name 
    ELSE dirty.name 
END AS new_name 
FROM dirty 
    LEFT JOIN clean ON clean.id = dirty.id 
ORDER BY dirty.id asc 

Example

+0

我認爲這是正確的軌道,但我怎麼會得到所有列上每個排,不只是名字? – WheatBeak

+0

@WheatBeak你是否試圖從每一行的兩個表中獲取所有列?只需在SELECT後用'*' –

+0

替換'dirty.id ... END AS new_name',就可以返回一個包含所有信息的大行。我想要得到的東西幾乎就是你的答案給了我的東西,但是也包括其他列,比如'電話','網站',它們都存在於兩個表中。我想也許每列都必須有一個'CASE'? – WheatBeak

1

似乎是一個LEFT JOIN是你所需要的:

SELECT COALESCE(pc.ID, p.ID), COALESCE(pc.Name, p.Name) 
FROM providers AS p 
LEFT JOIN providers_clean AS pc ON p.ID = pc.ID 

什麼這個查詢本質上是做:如果在「乾淨」表中存在的記錄,然後選擇這一項,否則選擇從一個'骯髒'的桌子。

+0

這是部分工作,但是,如果'clean'表中的列爲NULL,則結果將使用'dirty'表中的值。我猜這與Combisce有關,但我不太清楚這是如何工作的。 – WheatBeak

+0

@WheatBeak我認爲這是預期的結果:*給我所有來自供應商的'髒'結果排除'乾淨'的結果* –

1

,往往是指thisthis的連接的工作原理視覺解釋。

據他們說你需要一個完全外部聯接不包括兩個表中的項目( 「外不包括JOIN」):

SELECT * 
    FROM providers p 
    FULL OUTER JOIN providers_clean pc 
     ON pc.id = p.id 
WHERE p.id IS NULL OR pc.id IS NULL; 

更新遺憾的是沒有FULL OUTER JOIN在MySQL所以你必須效仿它。我以前this答案做到這一點:

select p.* 
    from providers p left join providers_clean pc on pc.id = p.id 
    where pc.id is null 
union all 
select pc.* 
    from providers p right join providers_clean pc on pc.id = p.id; 

的第一選擇是髒那些不乾淨的對口而第二選擇是簡單幹淨的。