2017-02-13 38 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