2011-09-13 37 views
4

我剛剛瞭解到COALESCE,我想知道是否可以在兩個表之間合併整行數據?如果不是的話,那麼下面的流傳最好的辦法是什麼?Sql COALESCE整行?

舉例來說,我有這兩個表,並假設所有列相匹配:

tbl_Employees

Id  Name  Email  Etc 
----------------------------------- 
1  Sue  ...  ... 
2  Rick  ...  ... 

tbl_Customers

Id  Name  Email  Etc 
----------------------------------- 
1  Bob  ...  ... 
2  Dan  ...  ... 
3  Mary  ...  ... 

而且具有ID的一個表:

tbl_PeopleInCompany

Id  CompanyId 
----------------- 
1  1 
2  1 
3  1 

我想查詢在獲得第一個錶行與ID匹配的一種方式中的數據,但如果沒有ID被發現從第二個表中獲取。

所以結果查詢將如下所示:

Id  Name  Email  Etc 
----------------------------------- 
1  Sue  ...  ... 
2  Rick  ...  ... 
3  Mary  ...  ... 

凡蘇和瑞克從第一臺拍攝,瑪麗從第二。

+2

「tbl_PeopleInId」表的用途是什麼?看起來你可以將'tbl_Employees'中的'FULL OUTER JOIN'加到'tbl_Customers'中以得到你想要的結果。另外我假設你沒有要求任何實際的目的。 –

+0

嘿馬丁,我想這個例子tbl_PeopleInIs太稀釋了。我編輯它以更好地理解。基本上是兩組數據之間關係的表格。 – Levitikon

回答

7
SELECT Id, Name, Email, Etc FROM tbl_Employees 
     WHERE Id IN (SELECT ID From tbl_PeopleInID) 
UNION ALL 
SELECT Id, Name, Email, Etc FROM tbl_Customers 
     WHERE Id IN (SELECT ID From tbl_PeopleInID) AND 
      Id NOT IN (SELECT Id FROM tbl_Employees) 

根據行的數量,有幾種不同的方式來編寫這些查詢(使用JOIN和EXISTS),但請先嚐試一下。

此查詢首先選擇tbl_Employees中目標列表中具有Id值的所有人員(表tbl_PeopleInID)。然後添加到這一堆行的「底部」第二個查詢的結果。第二個查詢將獲取所有tbl_Customer行,其中的目標列表爲,但不包括任何帶有出現在tbl_Employees中的ID的行。

總的清單包含你想要的人 - 來自tbl_PeopleInID的所有ID,優先給予員工,但缺少從客戶提取的記錄。

+0

我認爲這會很好。給我一個機會 – Levitikon

+0

+1首先避免空值,那麼你就不需要'COALESCE()'!儘管這個答案的敘述已經被「淡化」了,但代碼使用了聲音關係運算符:union,semi join('IN')和semi difference('NOT IN')。 – onedaywhen

0

我不認爲COALESCE函數可以用於你的想法。 COALESCE類似於ISNULL,但它可以讓你在列通過,將返回第一個非空值:

SELECT Name, Class, Color, ProductNumber, 
COALESCE(Class, Color, ProductNumber) AS FirstNotNull 
FROM Production.Product 

這篇文章應該解釋它的應用:

http://msdn.microsoft.com/en-us/library/ms190349.aspx

聽起來拉里·拉斯蒂格的回答更符合你需要的方式。

3

你也可以這樣做:

1)外連接上tbl_Employees.Id = tbl_Customers.Id兩個表。這將爲您提供tbl_Employees中的所有行,如果沒有匹配的行,則將tbl_Customers列保留爲空。

2)的應用情況,以選擇的tbl_Employees列或列tbl_Customers基於tbl_Customers.Id是否爲空,這樣的:

CASE WHEN tbl_Customers.Id IS NULL THEN tbl_Employees.Name ELSE tbl_Customers.Name END AS Name 

(我的語法可能不完美的存在,但該技術是健全的)。

+0

我試圖避免合併單個列,因爲這兩個表有很多列,可能會隨着時間而增長。 – Levitikon

+1

@JohnC如果'tbl_Employees.Name'非空,您可以使用'coalesce(tbl_Employees.Name,tbl_Customers.Name)Name',它具有相同的語義,而不是'case'。 – Josh

+0

@Levitikon:做一個「SELECT *」和「UNION ALL」是脆弱的。它要求兩張表永遠是完全一樣的。如果一列被添加到任何一個表中,它就會崩潰。爲了面對這種變化更具彈性,我建議指定列名。 – JohnC

0

這應該是非常高效的。它採用了CTE基本上建立一個沒有匹配的員工記錄客戶的一張小桌子,然後它只是UNION s表示與員工記錄

;WITH FilteredCustomers (Id, Name, Email, Etc) 
AS 
(
    SELECT Id, Name, Email, Etc 
    FROM tbl_Customers C 
      INNER JOIN tbl_PeopleInCompany PIC 
      ON C.Id = PIC.Id 
      LEFT JOIN tbl_Employees E 
      ON C.Id = E.Id 
    WHERE E.Id IS NULL 
) 

SELECT Id, Name, Email, Etc 
FROM tbl_Employees E 
     INNER JOIN tbl_PeopleInCompany PIC 
     ON C.Id = PIC.Id 

UNION 

SELECT Id, Name, Email, Etc 
FROM FilteredCustomers 

使用IN操作結果可能是相當繁重的大查詢,它可能必須評估正在處理的每個記錄的子查詢。

+0

問題上沒有標記表明這是SQL Server,因此用戶可能沒有CTE可用。此外,子查詢不需要按行評估,除非它們相關,而這些不是。 –

+0

非常公平,臨時表也可以取代上面的CTE: – ericb