2011-04-22 71 views
1

我有一個關於三元布爾邏輯的問題,它影響如何在我們的LINQ提供程序中實現多態實體之間的比較。用三元布爾邏輯比較SQL Server中的元組

在SQL中,如果你加入使用外鍵國家地區表:

SELECT * From Region r1, Region r2 
WHERE r1.Country == r2.Country 

(注:結果是相同的,你是否使用JOIN或WHERE synthax)

它將返回條件爲真的值,而不是條件爲假或未知(因爲某些鍵爲空)。因此,如果我們否定條件:

SELECT * From Region r1, Region r2 
WHERE r1.Country != r2.Country 

我們得到其中的條件爲真(今不同的密鑰)的值,我們將跳過具有相同鍵的,或者說有,因爲條件的一些空值的那些再次返回未知。即使我們這樣寫:

SELECT * From Region r1, Region r2 
WHERE not(r1.Country == r2.Country) 

未知將被傳播,所以空值不會出現在這個簡單的條件。到現在爲止還挺好。

現在讓我們想象一個地區可以有一個國家(小歐洲國家)或一個國家(美國,俄羅斯,中國......)。如果該地區有一個國家,它將有國家空白,反之亦然。

我們如何才能加入對[國家,國家],使其具有相同的屬性比以前?:

SELECT * From Region r1, Region r2 
WHERE r1.Country == r2.Country OR r1.State == r2.State 

如果它加入這個表達式將返回true,否則不明。我們希望,它僅在所有字段都爲空的情況下返回未知的,否則,如果我們否定:

SELECT * From Region r1, Region r2 
WHERE not(r1.Country == r2.Country OR r1.State == r2.State) 

它不返回行!如果我們嘗試更復雜的表達式:

SELECT * From Region r1, Region r2 
WHERE (r1.Country == r2.Country AND r1.Country IS NOT NULL AND r2.Country IS NOT NULL) 
    OR (r1.State == r2.State AND r1.State IS NOT NULL AND r2.State IS NOT NULL) 

然後它將在對匹配時返回true,否則返回false,並且從不爲空。然後,如果我們否定,它將返回所有行都爲空的值,其行爲與第一個示例中的行爲不同。

那麼用於比較這一對的表達式就像SQL平等一樣?

    匹配
  • 假時,當不匹配
  • 未知當一些操作數爲null
  • 真。

回答

2

創建一個計算列:

Location AS COALESCE(Country, State) 

,索引它和比較照常:

SELECT * 
FROM Region r1 
JOIN Region r2 
ON  r2.Location = r1.Location 

LocationNULL如果兩個CountryStateNULL

更新:

如果CountryState可以是幀間相媲美,創建一個額外的列表示哪一個被用於:

LocationType AS CASE WHEN Country IS NOT NULL THEN 1 WHEN State IS NOT NULL THEN 2 END, 
LocationId AS COALESCE(Country, State) 

,指數的兩個相比較使用它們:

SELECT * 
FROM Region r1 
JOIN Region r2 
ON  r2.LocationType = r1.LocationType 
     AND r2.LocationID = r1.LocationID 
+0

如果我這樣做,那麼我會將奧地利的地區(Id = 1的國家)與亞利桑那州(Id = 1的州)混合。我怎麼能讓他們不同? – Olmo 2011-04-22 09:32:52

+0

這肯定會工作,非常感謝。我不會走你自己的路,因爲這是一個通用的解決方案,我可以比較任何實體集合中的任何實體集合,而且我不希望將模型與計算字段和索引混淆,以便進行每種可能的比較。無論如何,你應該得到一票。 – Olmo 2011-04-22 09:52:29

+0

@Olmo:你可以在查詢中用它們的定義替換計算的字段:'ON CASE WHEN r1。... END = CASE WHEN r2。... END AND COALESCE(r1。...)= COALESCE(r2。...)',儘管它不可靠。請注意,使用「OR」解決方案時,比較次數將以二次方式增長。 – Quassnoi 2011-04-22 09:56:26

1

你可以試試這個:

SELECT * 
FROM Region r1 
    JOIN Region r2 
    ON (r1.Country = r2.Country 
     AND r1.State IS NULL 
     AND r2.State IS NULL 
     ) 
    OR (r1.State = r2.State 
     AND r1.Country IS NULL 
     AND r2.Country IS NULL 
     ) 
+0

Thnx。我想補充說你的表結構需要一些規範化來避免NULL。然後,您的查詢將不需要這種複雜的情況,對於大型表格可能會表現得很慢。你可能永遠看不到哪一個路線,世界上有多少個國家?儘管如此,最好在開始的時候考慮這個問題,而不是在以後可以在你的模式中添加分區域,城鎮和村莊,然後你突然意識到這個查詢是一個瓶頸。 – 2011-04-22 09:54:07

+0

當你用一個簡單的鍵[國家]加入一個元組[國家,州]時,我一直花時間概括你的解決方案。當你比較三重奏[國家,州,SpaceColony],與另一個三重奏,或與一個元組等...我們已經解決了這個問題,但我也考慮其他的解決方案,因爲它更容易理解,可能是索引如果必要。你怎麼看? – Olmo 2011-04-22 10:49:16

+0

我認爲你應該把它作爲一個單獨的問題與你的表結構(字段,主鍵和外鍵)一起發佈,因爲我們現在只能對結構進行猜測。 Quassnoi的建議(在一個字段中添加'Country'和'State'並添加一個'LocationType'似乎是最好的,但是顯示其他相關表格將有助於理解問題並提出可能的重構/標準化。 – 2011-04-22 10:55:57