2013-04-09 5 views
3

Представьте таблицу (с именем Example) с одним полем первичного ключа (KeyID), а также поле внешнего ключа (ForeignID). Этот внешний ключ используется для связывания строк в нашей таблице с чужой строкой/элементом в отдельной таблице, устанавливая отношения «много-к-одному». Однако для многих наших строк таких отношений нет, поэтому наше поле внешнего ключа находится в этих строках NULL.Что делать в SQL, если вы хотите, чтобы NULL = NULL был правдой?

Теперь, если нам задан один ключевой код (например, 123), что является предпочтительным SQL для получения набора результатов, содержащего , все строки, которые имеют соответствующее значение ForeignID?

я простодушно начал со следующим SQL:

SELECT E1.* 
FROM Example E1 
JOIN Example E2 
    ON E2.KeyID = 123 
    AND E2.ForeignID = E1.ForeignID 

Это работает просто замечательно, когда наше соответствие ключевой строка имеет нормальное значение в ForeignID. Тем не менее, он терпит неудачу (ничего не возвращает), если ForeignID оказывается NULL. После некоторого первоначального поиска я теперь понимаю, почему (после чтения таких вопросов, как this one), но я не нашел хороших решений для того, как обойти это ограничение.

Предоставленный SQL Server имеет параметр ANSI_NULLS, который я могу изменить, но это похоже на грязный, потенциально проблематичный взлом.

В качестве альтернативы, я мог бы всегда составлять собственное псевдо-нулевое значение (например, 0) и вставлять его в столбец ForeignID вместо NULL, но это нарушит ограничение внешнего ключа, которое я установил для этого столбца.

Итак, как лучше всего достичь того, что я хочу?

ответ

8

непроверенная, но я думаю, что вы могли бы сделать это:

SELECT E1.* 
FROM Example E1 
JOIN Example E2 
    ON E2.KeyID = 123 
    AND (E2.ForeignID = E1.ForeignID 
    OR (E2.ForeignID IS NULL AND E1.ForeignID IS NULL)) 

Edit: Works, SQL Скрипки here

+2

Вы, вероятно, следует поставить некоторые скобки там сделать более очевидным то, что вы делаете, как для OP, так и для SQL Server – Blorgbeard

+0

Duh, ответ прост, прост и понятен, поэтому, конечно, я сам не думал об этом. -_- – Jeremy

+0

Обратите внимание, что это приведет к декартовому объединению строк NULL из E1 с NULL-строками из E2. Пока одна из таблиц имеет только одну строку с NULL, вы должны быть в порядке. –

7

You can also do

SELECT E1.* 
FROM Example E1 
     JOIN Example E2 
     ON E2.KeyID = 123 
      AND EXISTS (SELECT E2.ForeignID 
         INTERSECT 
         SELECT E1.ForeignID) 
+0

Хотя 'INTERSECT' недоступен в некоторых из баз данных, которые я использую, я начинаю понимать, насколько это полезно. Этот ответ также привел меня к следующему полезному блогу: [Недокументированные планы запросов: сравнительные сравнения] (http://sqlblog.com/blogs/paul_white/archive/2011/06/22/undocumented-query-plans-equality-comparisons. ASPX). – Jeremy

Смежные вопросы