在条件中编写具有可为空值的准备好的语句
Write a prepared statement with nullable values in conditions
有没有办法编写一个准备好的语句,其中一个值与条件中的另一个值进行比较,我不知道这个值是否 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
MySQL 提供了一个 null-safe 比较 <=>
(宇宙飞船)运算符。这指定了一个相等比较,它将 return TRUE 或 FALSE,并且当任一操作数为 NULL 时不会 return NULL。
作为演示:
SELECT NULL=NULL
, NULL<=>NULL
, 1=NULL
, 1<=>NULL
, 1=0
, 1<=>0
, 1=1
, 1<=>1
Returns:
NULL=NULL NULL<=>NULL 1=NULL 1<=>NULL 1=0 1<=>0 1=1 1<=>1
--------- ----------- ------ -------- ------ ----- ------ -----
(NULL) 1 (NULL) 0 0 0 1 1
那个比较操作本质上就是shorthand。 return 来自:
a <=> b
相当于
中的 return
( a = b OR ( a IS NULL AND b IS NULL ) )
要回答您提出的问题,我们可以使用 NULL-safe 比较 <=>
(宇宙飞船)运算符编写一个语句,如下所示:
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 版本中是否仍然如此。)如上所示,解决方法是在语句中使用 four 个不同的占位符,并为:a1
和 :a1d
.)
有没有办法编写一个准备好的语句,其中一个值与条件中的另一个值进行比较,我不知道这个值是否 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
MySQL 提供了一个 null-safe 比较 <=>
(宇宙飞船)运算符。这指定了一个相等比较,它将 return TRUE 或 FALSE,并且当任一操作数为 NULL 时不会 return NULL。
作为演示:
SELECT NULL=NULL
, NULL<=>NULL
, 1=NULL
, 1<=>NULL
, 1=0
, 1<=>0
, 1=1
, 1<=>1
Returns:
NULL=NULL NULL<=>NULL 1=NULL 1<=>NULL 1=0 1<=>0 1=1 1<=>1
--------- ----------- ------ -------- ------ ----- ------ -----
(NULL) 1 (NULL) 0 0 0 1 1
那个比较操作本质上就是shorthand。 return 来自:
a <=> b
相当于
中的 return ( a = b OR ( a IS NULL AND b IS NULL ) )
要回答您提出的问题,我们可以使用 NULL-safe 比较 <=>
(宇宙飞船)运算符编写一个语句,如下所示:
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 版本中是否仍然如此。)如上所示,解决方法是在语句中使用 four 个不同的占位符,并为:a1
和 :a1d
.)