2017-02-13 7 views
4

Есть ли способ написать подготовленный оператор, где значение сравнивается с другим значением в состоянии, и я не знаю, является ли это значение NULL или нет.Напишите подготовленный оператор с нулевыми значениями в условиях

SELECT `foo` FROM `bar` WHERE `a1` = :a1 AND `a2` = :a2 

Если я хотел бы использовать это подготовленное заявление с a1 => null и a2 => 42, то результирующий запрос будет:

SELECT `foo` FROM `bar` WHERE `a1` = NULL AND `a2` = '42' 

Это, конечно, не то, что я хочу. Я должен был бы это в этом случае:

SELECT `foo` FROM `bar` WHERE `a1` IS NULL AND `a2` = '42' 
            ^^ 

Оба a1 и a2 являются обнуляемым. Я не хочу, чтобы определить-подготовить заявление:

-- I would use this, if both values are not null 
SELECT `foo` FROM `bar` WHERE `a1` = :a1 AND `a2` = :a2 

-- and this, if the expected value of a1 is null 
SELECT `foo` FROM `bar` WHERE `a1` IS NULL AND `a2` = :a2 

-- and this, if the expected value of a2 is null 
SELECT `foo` FROM `bar` WHERE `a1` = :a1 AND `a2` IS NULL 

-- and this, if I would expect both values to be null 
SELECT `foo` FROM `bar` WHERE `a1` IS NULL AND `a2` IS NULL 

ответ

4

MySQL обеспечивает <=> (космический корабль) оператора нулевого безопасного сравнения. Это указывает сравнение равенства, которое вернет TRUE или FALSE, и не вернет NULL, если один из операндов NULL.

В качестве демонстрации:

SELECT NULL=NULL 
    , NULL<=>NULL 
    , 1=NULL 
    , 1<=>NULL 
    , 1=0 
    , 1<=>0 
    , 1=1 
    , 1<=>1 

Возвращает:

NULL=NULL NULL<=>NULL 1=NULL 1<=>NULL  1=0 1<=>0  1=1 1<=>1 
--------- ----------- ------ -------- ------ ----- ------ ----- 
    (NULL)   1 (NULL)   0  0  0  1  1 

Эта операция сравнения по существу сокращенная. Возвращение из:

a <=> b 

эквивалентно возвращению из

(a = b OR (a IS NULL AND b IS NULL)) 

Чтобы ответить на вопрос, который вы просили, мы могли бы написать заявление с помощью нуль-сейф Сравнение <=> (космический корабль), например:

SELECT `foo` 
    FROM `bar` 
    WHERE `a1` <=> :a1 
    AND `a2` <=> :a2 

Или, для более стандартов ANSI совместимого и портативного подхода, мы могли бы добиться того же результата без использования этого конкретного оператора MySQL, например:

SELECT `foo` 
    FROM `bar` 
    WHERE (`a1` = :a1 OR (`a1` IS NULL AND :a1d IS NULL)) 
    AND (`a2` = :a2 OR (`a2` IS NULL AND :a2d IS NULL)) 

Обратите внимание, что мы должны передать в стоимости каждой привязки значение два раза. Раньше PDO не разрешало более чем одной ссылки на привязку привязки. (Не уверен, если это все еще происходит в более поздних версиях PDO.) Обходной, как было показано выше, заключается в использовании четыре различных заполнителей в заявлении, и поставить такое же значение для :a1 и :a1d.)

+0

Спасибо! Не знал этого оператора (и мог подумать о решении с «OR» вне себя ..!) – stofl

+1

@stofl: Я рад, что вы нашли это полезным. Чтобы выделить что-то, я, возможно, недостаточно подчеркнул ... что ** '<=>' ** оператор сравнения * * нестандартное * расширение доступно * только * в MySQL. (По крайней мере, я не знаю каких-либо других СУБД, которые поддерживают этот оператор.) – spencer7593

+0

Благодарим вас за это. Это не имеет значения в моем случае, потому что мы не остаемся независимыми от dbms. – stofl

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