Напишите подготовленное утверждение с обнуляемыми значениями в условиях

Есть ли способ написать подготовленный оператор, где значение сравнивается с другим значением в условии, и я не знаю, является ли это значение 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 обнуляемы Я не хочу определять 4 подготовительных заявления:

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

Чтобы ответить на вопрос, который вы задали, мы могли бы написать утверждение, используя 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.)

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]