2017-02-13 47 views
4

有没有办法编写一个准备好的语句,其中的值与条件中的另一个值进行比较,我不知道这个值是否为NULL在条件中编写一个可以为空的值的准备语句

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

如果我会使用与a1 => nulla2 => 42这个准备好的语句,然后将得到的查询是:

SELECT `foo` FROM `bar` WHERE `a1` = 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 

回答

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相同的值。)

+0

谢谢!不知道那个操作员(并且可以用自己的'OR'算出解决方案..!) – stofl

+1

@stofl:很高兴你发现这有帮助。突出一些我可能没有充分强调的东西...... **'<=> **比较运算符是MySQL中可用的*非标准*扩展*只*。 (至少,我不知道有任何其他DBMS支持这个操作符。) – spencer7593

+0

谢谢你提到这一点。这与我的情况无关,因为我们不会一直保持dbms独立。 – stofl