2010-01-22 115 views
0

我想將此SQL轉換爲LINQ。 (它shouldl選擇從表生產根據3列不存在的輸入行如果兩個表中一列包含NULL,它應該被認爲是具有相同的值。)將此SQL查詢轉換爲Linq(不存在+子查詢)

SELECT i.* FROM INPUT AS i 
WHERE NOT EXISTS 
(SELECT p.Agent FROM Production AS p 
WHERE ISNULL(i.CustID,'') <> ISNULL(p.CustID,'') 
AND ISNULL(i.CustName,'') <> ISNULL(p.CustName,'') 
AND ISNULL(i.household,'') <> ISNULL(p.Household,'')) 

回答

4

首先的 - 這不是一個好的SQL查詢。每一列都被封裝在一個非sargable函數中,這意味着引擎將無法利用這些列上的任何索引(假設您有任何)。

首先讓我們來重寫這是一個半體面的SQL查詢:

SELECT i.* 
FROM Input i 
LEFT JOIN Production p 
    ON (p.CustID = i.CustID OR (p.CustID IS NULL AND i.CustID IS NULL)) 
    AND (p.CustName = i.CustName OR (p.CustName IS NULL AND i.CustName IS NULL)) 
    AND (p.Household = i.Household OR 
     (p.Household IS NULL AND i.Household IS NULL)) 
WHERE p.CustID IS NULL 

現在,話雖如此,LEFT JOIN/IS NULL不是很大的效率下去,但我們並沒有太多的選擇這裏,是因爲我們比較多列。根據你的列名,我開始懷疑這個模式是否被正確化了。一個CustID應該最有可能與一個並且只有一個CustName關聯 - 事實上,你必須比較這兩個似乎有點奇怪。和Household - 我不確定這是什麼,但如果它是一個varchar(x)/nvarchar(x)列,那麼我想知道它是否也可能與客戶有1:1的關係。

如果我在這裏猜測太多,可隨意解開本段;但爲了以防萬一,我想說的是,如果數據沒有正確標準化,規範化,將使它更容易和更快地對查詢:

SELECT * 
FROM Input 
WHERE CustID NOT IN (SELECT CustID FROM Production) 

不管怎樣,回到第一個查詢,因爲這是我們現在需要處理的。不幸的是,這是不可能建立在LINQ的那些特定條件下加入的,所以我們需要重寫SQL查詢的東西略差(因爲我們現在有從Input讀兩次):

SELECT * 
FROM Input 
WHERE <Primary Key> NOT IN 
(
    SELECT i.<Primary Key> 
    FROM Input i 
    INNER JOIN Production p 
    ON (p.CustID = i.CustID OR (p.CustID IS NULL AND i.CustID IS NULL)) 
    AND (p.CustName = i.CustName OR (p.CustName IS NULL AND i.CustName IS NULL)) 
    AND (p.Household = i.Household OR 
     (p.Household IS NULL AND i.Household IS NULL)) 
) 

現在我們有一些我們最終可以轉化爲Linq語法。我們仍然不能明確地加入,這是最好的,但我們走老派,從笛卡爾連接開始,將連接條件拋到WHERE段,服務器仍然可以將它整理出來:

var excluded = 
    from i in input 
    from p in production 
    where 
     ((p.CustID == i.CustID) || ((p.CustID == null) && (i.CustID == null))) && 
     ((p.CustName == i.CustName) || 
      ((p.CustName == null) && (i.CustName == null))) && 
     ((p.Household == i.Household) || 
      ((p.Household == null) && (i.Household == null))); 
    select i.PrimaryKey; 

var results = 
    from i in input 
    where !excluded.Contains(i.PrimaryKey) 
    select i; 

我在這裏假設你在表上有某種主鍵。如果不這樣做,你有其他的問題,但你可以避開使用此特定問題EXCEPT

var excluded = 
    from i in input 
    from p in production 
    where 
     ((p.CustID == i.CustID) || ((p.CustID == null) && (i.CustID == null))) && 
     ((p.CustName == i.CustName) || 
      ((p.CustName == null) && (i.CustName == null))) && 
     ((p.Household == i.Household) || 
      ((p.Household == null) && (i.Household == null))); 
    select i; 

var results = input.Except(excluded); 
+0

SQL聯接不在這裏工作了,因爲它會從第二個表中返回的每一行的地方3列匹配。我只需要一行。列名僅用於說明。沒有主鍵和ID列不相關。每個表的ID都是唯一的,所以它不能被使用。你的LINQ給了我一些指針。謝謝。 – 2010-01-22 17:50:26

+0

@Tony_Henrich:如果右表中有多個匹配的行,那麼你是對的,第一個查詢將返回重複的行。然而,我寫的後續查詢不會有這個問題,Linq查詢會做你想做的事情(包括最後一個如果沒有PK ......但我真的會建議不要PK,這個例子是一個很好的例子說明爲什麼它們很重要)。 – Aaronaught 2010-01-22 17:58:34

+0

簡而言之,這些表格實際上是Excel電子表格。我已將數據複製到SQL Server以驗證操作。主鍵不會幫助,因爲沒有候選人。每個表中唯一的ID列對該表是唯一的。這些值在表格之間不匹配。 – 2010-01-22 18:28:35