Почему НЕ выполняется в SQL Server & ldquo; break & rdquo; когда список содержит значение NULL? [Дубликат]

Если вам известен путь класса или jar, содержащий класс, то добавьте его в свой путь к классу во время его запуска. Вы можете использовать путь к классам, как указано здесь:

в Windows

java -classpath .;yourjar.jar YourMainClass

в UNIX / Linux

java -classpath .:yourjar.jar YourMainClass
206
задан gotqn 28 July 2015 в 12:00
поделиться

11 ответов

Запрос A совпадает с:

select 'true' where 3 = 1 or 3 = 2 or 3 = 3 or 3 = null

Так как 3 = 3 истинно, вы получаете результат.

Запрос B такой же, как:

select 'true' where 3 <> 1 and 3 <> 2 and 3 <> null

Когда ansi_nulls включен, 3 <> null НЕИЗВЕСТНО, поэтому предикат оценивает UNKNOWN, и вы не получите никаких строк.

Когда ansi_nulls выключен, 3 <> null истинно, поэтому предикат оценивает значение true, и вы получаете строку.

230
ответ дан Brannon 22 August 2018 в 08:21
поделиться
  • 1
    Кто-нибудь когда-либо указывал, что преобразование NOT IN в серию <> and изменяет семантическое поведение не в этом наборе на что-то еще? – Ian Boyd 13 October 2010 в 15:47
  • 2
    @Ian - Похоже, что «A NOT IN (« X »,« Y »)» фактически является псевдонимом для A & lt; gt; 'X' и A & lt; & gt; «Y» в SQL. (Я вижу, что вы обнаружили это самостоятельно в stackoverflow.com/questions/3924694/… , но хотели убедиться, что ваше возражение было рассмотрено в этом вопросе.) – Ryan Olson 27 December 2010 в 20:21
  • 3
    Полагаю, это объясняет, почему SELECT 1 WHERE NULL NOT IN (SELECT 1 WHERE 1=0); дает строку вместо пустых результатов, которые я ожидал. – binki 23 August 2016 в 16:30
  • 4
    Это очень плохое поведение SQL-сервера, потому что, если он ожидает NULL-сравнения с использованием «IS NULL», тогда он должен расширить предложение IN к такому же поведению и не глупо применять к себе неправильную семантику. – OzrenTkalcecKrznaric 15 September 2016 в 09:47
  • 5
    @binki, запрос выполняется, если вы запустите здесь rextester.com/l/sql_server_online_compiler , но не работает, если вы запустите здесь sqlcourse.com/cgi-bin/interpreter.cgi . – Istiaque Ahmed 10 November 2017 в 14:57

это для Мальчика:

select party_code 
from abc as a
where party_code not in (select party_code 
                         from xyz 
                         where party_code = a.party_code);

работает независимо от настроек ansi

1
ответ дан C B 22 August 2018 в 08:21
поделиться
  • 1
    для исходного вопроса: B: выберите 'true', где 3 не в (1, 2, null) способ удаления нулей должен быть выполнен, например. выберите «true», где 3 не в (1, 2, isnull (null, 0)) общая логика, если NULL является причиной, затем найдите способ удаления значений NULL на некотором шаге запроса. – user 23 June 2009 в 12:20
  • 2
    выберите party_code из abc, где отсутствует параметр party_code (выберите party_code из xyz, где party_code не является нулевым), но удачи, если вы забыли поле, допускают нули, что часто бывает – user 24 June 2009 в 07:42

Null означает и отсутствие данных, то есть неизвестно, а не значение данных ничего. Это очень легко для людей из программирования, чтобы смутить это, потому что в языках типов C при использовании указателей null действительно ничего.

Следовательно, в первом случае 3 действительно находится в наборе (1,2,3, null), так что true возвращается

Во втором, однако, вы можете уменьшить его до

select 'true', где 3 не в (null)

Таким образом, ничего не возвращается, потому что анализатор ничего не знает о наборе, с которым вы его сравниваете, - это а не пустой набор, но неизвестный набор. Использование (1, 2, null) не помогает, потому что набор (1,2), очевидно, является ложным, но тогда вы и против этого неизвестны, что неизвестно.

6
ответ дан Cruachan 22 August 2018 в 08:21
поделиться

В A, 3 проверяется на равенство по отношению к каждому члену набора, что дает (FALSE, FALSE, TRUE, UNKNOWN). Поскольку один из элементов TRUE, условие TRUE. (Также возможно, что здесь происходит короткое замыкание, поэтому он фактически останавливается, как только он достигает первого ИСТИНА и никогда не оценивает 3 = NULL.)

В B, я думаю, он оценивает условие как NOT (3 в (1,2, null)). Тестирование 3 для равенства по отношению к установленным доходностям (FALSE, FALSE, UNKNOWN), которое агрегируется в UNKNOWN. NOT (UNKNOWN) дает UNKNOWN. Таким образом, общая истина условия неизвестна, которая в конце по существу трактуется как ЛОЖЬ.

6
ответ дан Dave Costa 22 August 2018 в 08:21
поделиться

NOT IN возвращает 0 записей при сравнении с неизвестным значением

Поскольку NULL является неизвестным, запрос NOT IN, содержащий NULL или NULL s в списке возможных значения всегда будут возвращать записи 0, так как нет способа убедиться, что значение NULL не является тестируемым значением.

15
ответ дан Govind Rai 22 August 2018 в 08:21
поделиться
  • 1
    Это ответ в двух словах. Я нашел это легче понять даже без какого-либо примера. – Govind Rai 13 September 2016 в 17:31

Всякий раз, когда вы используете NULL, вы действительно имеете дело с трехзначной логикой.

Ваш первый запрос возвращает результаты, поскольку предложение WHERE оценивается как:

    3 = 1 or 3 = 2 or 3 = 3 or 3 = null
which is:
    FALSE or FALSE or TRUE or UNKNOWN
which evaluates to 
    TRUE

Второй :

    3 <> 1 and 3 <> 2 and 3 <> null
which evaluates to:
    TRUE and TRUE and UNKNOWN
which evaluates to:
    UNKNOWN

UNKNOWN не совпадает с FALSE, вы можете легко проверить его, вызвав:

select 'true' where 3 <> null
select 'true' where not (3 <> null)

Оба запроса не дадут вам результатов

Если UNKNOWN был таким же, как FALSE, то, предполагая, что первый запрос даст вам FALSE, второй должен был бы оценивать значение TRUE, поскольку он был бы таким же, как NOT (FALSE). Это не так.

В SqlServerCentral есть очень хорошая статья .

Вся проблема NULL и трехзначной логики может сначала немного сбив с толку, но для того, чтобы писать правильные запросы в TSQL

, необходимо понимать другую статью, которую я бы рекомендовал: SQL Aggregate Functions и NULL .

49
ответ дан MartyMacGyver 22 August 2018 в 08:21
поделиться

ЕСЛИ вы хотите фильтровать с помощью NOT IN для подзапроса, содержащего NULL, просто проверьте не null

SELECT blah FROM t WHERE blah NOT IN
        (SELECT someotherBlah FROM t2 WHERE someotherBlah IS NOT NULL )
4
ответ дан Mihai 22 August 2018 в 08:21
поделиться
  • 1
    У меня возникла проблема с внешним запросом соединения, который не возвращал никаких записей в особых ситуациях, поэтому проверил это решение как для сценария Null, так и для существующих записей, и это сработало для меня. Если возникнут другие проблемы, я буду упоминать здесь, спасибо. – QMaster 23 February 2018 в 23:00

также может быть полезно знать логическую разницу между соединением, существует и в http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx

0
ответ дан Mladen 22 August 2018 в 08:21
поделиться

Из ответов здесь можно сделать вывод, что NOT IN (subquery) неправильно обрабатывает нули и его следует избегать в пользу NOT EXISTS. Однако такой вывод может быть преждевременным. В следующем сценарии, зачисленном в Chris Date (Database Programming and Design, Vol 2 No 9, September 1989), NOT IN обрабатывает нули правильно и возвращает правильный результат, а не NOT EXISTS.

Рассмотрим таблицу sp для представления поставщиков (sno), которые, как известно, поставляют детали (pno) в количестве (qty). В таблице в настоящее время хранятся следующие значения:

      VALUES ('S1', 'P1', NULL), 
             ('S2', 'P1', 200),
             ('S3', 'P1', 1000)

Обратите внимание, что количество является нулевым, т. Е. Для записи факта, что поставщик, как известно, предоставляет детали, даже если в каком количестве неизвестно.

Задача состоит в том, чтобы найти поставщиков, которые известны номером запасной части «P1», но не в количествах 1000.

Следующие правила используют NOT IN для правильной идентификации поставщика S2, only:

WITH sp AS 
     ( SELECT * 
         FROM ( VALUES ( 'S1', 'P1', NULL ), 
                       ( 'S2', 'P1', 200 ),
                       ( 'S3', 'P1', 1000 ) )
              AS T ( sno, pno, qty )
     )
SELECT DISTINCT spx.sno
  FROM sp spx
 WHERE spx.pno = 'P1'
       AND 1000 NOT IN (
                        SELECT spy.qty
                          FROM sp spy
                         WHERE spy.sno = spx.sno
                               AND spy.pno = 'P1'
                       );

Однако в нижеприведенном запросе используется одна и та же общая структура, но с NOT EXISTS, но неверно включает в себя поставщик S1 в результате (т.е. для которого значение равно null):

WITH sp AS 
     ( SELECT * 
         FROM ( VALUES ( 'S1', 'P1', NULL ), 
                       ( 'S2', 'P1', 200 ),
                       ( 'S3', 'P1', 1000 ) )
              AS T ( sno, pno, qty )
     )
SELECT DISTINCT spx.sno
  FROM sp spx
 WHERE spx.pno = 'P1'
       AND NOT EXISTS (
                       SELECT *
                         FROM sp spy
                        WHERE spy.sno = spx.sno
                              AND spy.pno = 'P1'
                              AND spy.qty = 1000
                      );

Таким образом, NOT EXISTS не является серебряной пулей, она, возможно, появилась!

Конечно, источником проблемы является наличие нулей, поэтому «реальным» решением является устранение эти нули.

Это может быть достигнуто (среди других возможных конструкций) с использованием двух таблиц:

  • sp поставщиков, которые, как известно, поставляют детали
  • spq поставщиков, которые, как известно, поставляют детали в известных количествах

, отметив, что, вероятно, должно быть ограничение внешнего ключа, где spq ссылается sp.

Результат может тогда быть получена с использованием реляционного оператора «минус» (являющегося ключевым словом EXCEPT в стандартном SQL), например

WITH sp AS 
     ( SELECT * 
         FROM ( VALUES ( 'S1', 'P1' ), 
                       ( 'S2', 'P1' ),
                       ( 'S3', 'P1' ) )
              AS T ( sno, pno )
     ),
     spq AS 
     ( SELECT * 
         FROM ( VALUES ( 'S2', 'P1', 200 ),
                       ( 'S3', 'P1', 1000 ) )
              AS T ( sno, pno, qty )
     )
SELECT sno
  FROM spq
 WHERE pno = 'P1'
EXCEPT 
SELECT sno
  FROM spq
 WHERE pno = 'P1'
       AND qty = 1000;
8
ответ дан onedaywhen 22 August 2018 в 08:21
поделиться
  • 1
    Я, честно говоря, не думал, что есть что сказать по этому поводу. Интересно. – Jamie Ide 24 September 2011 в 20:54
  • 2
    @Jamie Ide: На самом деле, у меня есть еще один ответ на этот вопрос: потому что NOT IN (subquery), включающий в себя нули, может дать неожиданные результаты, возникает соблазн полностью избегать IN (subquery) и всегда использовать NOT EXISTS (subquery) (как я когда-то сделал!), Потому что кажется, что он всегда обрабатывает нули правильно. Однако бывают случаи, когда NOT IN (subquery) дает ожидаемый результат, тогда как NOT EXISTS (subquery) дает неожиданные результаты! Я могу обойтись, чтобы написать это, но если я смогу найти свои заметки по этому вопросу (нужны заметки, потому что это неинтуитивно!) Заключение одно и то же: избегайте нулей! – onedaywhen 26 September 2011 в 08:18
  • 3
    О, мой бог. Спасибо, что написали это ... это сводило меня с ума .. – Govind Rai 13 September 2016 в 17:24

Сравнение с null не определено, если вы не используете IS NULL.

Итак, при сравнении 3 с NULL (запрос A) он возвращает undefined.

I.e. SELECT 'true', где 3 in (1,2, null) и SELECT 'true', где 3 не в (1,2, null)

, выдаст тот же результат, что и NOT (UNDEFINED) undefined, но не TRUE

18
ответ дан Sunny Milenov 22 August 2018 в 08:21
поделиться
  • 1
    Отличная точка. выберите 1, где null в (null) не возвращает строки (ansi). – crokusek 18 July 2012 в 01:52
8
ответ дан onedaywhen 5 November 2018 в 05:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: