在条件中编写具有可空值的预准备语句

时间:2017-02-13 21:40:16

标签: php mysql pdo prepared-statement nullable

有没有办法写一个准备好的陈述,其中一个值与一个条件中的另一个值进行比较,我不知道这个值是否为NULL

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

如果我将此预准备语句与a1 => nulla2 => 42一起使用,则生成的查询将为:

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

这当然不是我想要的。在那种情况下我需要这个:

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

a1a2都可以为空。我不想定义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

1 个答案:

答案 0 :(得分: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中是否仍然如此。)如上所示,解决方法是在语句中使用四个不同的占位符,并为{{1提供相同的值}和:a1。)