2013-04-03 18 views
2

我有一個五十萬記錄表,我需要找到重複項。所以我用這個代碼,我創建:linq sql查找重複項,但採取空和空字符串作爲相同

var dups2 = from m in mg_B 
    group m by new { m.Addr1, m.Addr2, m.City, m.State } 
    into g 
    where g.Count() > 1 
    select g; 

這段代碼的問題是,它不會採取爲重複2條已ADDR1爲空字符串「」,並分別NULL。

基本上,當比較字段的空值和空值時,它將它們視爲不同,但我需要將其視爲相同。

我知道我可以通過每一個記錄並用「」替換空值,但我花了1分鐘時間通過4000條記錄。當有人點擊一個按鈕時,這將重複進行。

我發現了這個null空字符串的問題,因爲我最初創建了一個只有一些字段的類(該表有40多個字段)。

List<CombineClass> mg = (from m in db.MG_Backup 
    where m.IsArchived == false 
    select new CombineClass { id = m.ID, name = m.Name, addr1 = string.IsNullOrEmpty(m.Addr1) ? "" : m.Addr1, addr2 = string.IsNullOrEmpty(m.Addr2) ? "" : m.Addr2, city = m.City, state = m.State }).ToList(); 

任何想法?

+0

第二個例子會發生什麼?你是說這個人有效,但是不可取,因爲你必須對它進行檢查和制定?一個空字符串和null是非常不同的東西,如果這就是你所要求的,你就不能告訴語言去處理它們。 –

+0

在第一個示例中,它找到6000條記錄,在第二個示例中找到7000條記錄 – Nathan

+0

通過實施,您可以實現自己的[comparer](http://msdn.microsoft.com/zh-cn/library/bb534334.aspx) [的IEqualityComparer](http://msdn.microsoft.com/en-us/library/ms132151.aspx)。然後,您的比較器將通過將空字符串和空字符串視爲相同來執行比較**。我懷疑它會很快 - 它仍然需要從數據庫中提取所有記錄並處理C#端。你最好的選擇是修復數據庫,使其只有'NULL',用於沒有AddrLine1的記錄(因爲這在語義上是正確的)。 –

回答

2

此版本與兼容的LINQ到SQL/LINQ到實體

var dups2 = from m in mg_B 
    group m by new 
    { 
     Addr1 = m.Addr1 ?? string.Empty, 
     Addr2 = m.Addr2 ?? string.Empty, 
     City = m.City ?? string.Empty, 
     State = m.State ?? string.Empty, 
    } 
    into g 
    where g.Count() > 1 
    select g; 

生成的SQL看起來有點像這樣:

-- Parameters 
DECLARE @p0 NVarChar(1000) = '' 
DECLARE @p1 NVarChar(1000) = '' 
DECLARE @p2 NVarChar(1000) = '' 
DECLARE @p3 NVarChar(1000) = '' 
DECLARE @p4 Int = 1 

SELECT [t2].[value2] AS [Addr1], [t2].[value22] AS [Addr2], [t2].[value3] AS [City], [t2].[value3] AS [State] 
FROM (
    SELECT COUNT(*) AS [value], [t1].[value] AS [value2], [t1].[value2] AS [value22], [t1].[value3], [t1].[value4] 
    FROM (
     SELECT COALESCE([t0].[Addr1],@p0) AS [value], COALESCE([t0].[Addr2],@p1) AS [value2], COALESCE([t0].[City],@p2) AS [value3], COALESCE([t0].[State],@p3) AS [value4] 
     FROM [SettingSystemNodes] AS [t0] 
     ) AS [t1] 
    GROUP BY [t1].[value], [t1].[value2], [t1].[value3], [t1].[value4] 
    ) AS [t2] 
WHERE [t2].[value] > @p4 

需要注意的是你,如果你設置string.Empty到一個局部變量之前或者甚至是一個let變量在查詢中,只有一個參數將被用於空字符串。

0

那麼這裏的蠻力方式:

var dups2 = from m in mg_B 
    group m by new { 
     Addr1 = (string.IsNullOrEmpty(m.Addr1) ? "" : m.Addr1), 
     Addr2 = (string.IsNullOrEmpty(m.Addr2) ? "" : m.Addr2), 
     City = (string.IsNullOrEmpty(m.City) ? "" : m.City), 
     State = (string.IsNullOrEmpty(m.State) ? "" : m.State), 
     ... 
     } 
    into g 
    where g.Count() > 1 
    select g; 

如果你想代碼清潔你可能會對string擴展方法:

public static string EmptyForNull(this string s) 
{ 
    return string.IsNullOrEmpty(s) ? "" : s; 
} 

,然後你的查詢會:

var dups2 = from m in mg_B 
    group m by new { 
     Addr1 = EmptyForNull(m.Addr1), 
     Addr2 = EmptyForNull(m.Addr2), 
     City = EmptyForNull(m.City), 
     State = EmptyForNull(m.State), 
     ... 
     } 
    into g 
    where g.Count() > 1 
    select g; 

Howev呃,如果它是用SQL而不是Linq完成的,那麼這可能會更快。

+0

這是我在寫帖子之前嘗試的第一件事,它不工作......它只是使標準「」或addr1 ... – Nathan

+1

Nooooo!我的眼睛流血了!使用null合併,它正確轉換爲ISNULL。 'Addr1 = m.Addr1 ?? string.Empty' – SPFiredrake