сравнение кортежей в SQL Server с троичной булевой логикой - PullRequest
1 голос
/ 22 апреля 2011

У меня есть вопрос относительно троичной логической логики, которая влияет на то, как реализовать сравнение между полиморфными сущностями в нашем поставщике LINQ.

В 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?

  • Истина, когда совпадает
  • Ложь, когда не совпадает
  • Неизвестно, если какой-либо операнд равен нулю.

Ответы [ 2 ]

2 голосов
/ 22 апреля 2011

Создайте вычисляемый столбец:

Location AS COALESCE(Country, State)

, индексируйте его и сравните, как обычно:

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

Location будет NULL, если оба Country и State are NULL.

Обновление:

Если Country и State могут быть взаимно сопоставимыми, создайте дополнительный столбец, показывающий, какой из них используется:

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
1 голос
/ 22 апреля 2011

Можете ли вы попробовать это:

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
       )
...