Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
441 views
in Technique[技术] by (71.8m points)

php - Write a prepared statement with nullable values in conditions

Is there a way to write a prepared statement where a value is compared to another value in a condition and I don't know, whether this value is NULL or not.

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

If I would use this prepared statement with a1 => null and a2 => 42, then the resulting query would be:

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

This is, of course, not what I want. I would need this in that case:

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

Both a1 and a2 are nullable. I don't want to define 4 prepare statements:

-- 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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

MySQL provides a null-safe comparison <=> (spaceship) operator. That specifies an equality comparison that will return TRUE or FALSE, and won't return NULL when either of the operands is NULL.

As a demonstration:

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

That comparison operation is essentially shorthand. The return from:

 a <=> b

Is equivalent to the return from

 ( a = b OR ( a IS NULL AND b IS NULL ) )

To answer the question you asked, we could write a statement using the NULL-safe comparison <=> (spaceship) operator, like this:

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

Or, for a more ANSI standards compliant and portable approach, we could achieve the same result without using that MySQL specific operator, like this:

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

Note that we need to pass in the value of each bind value two times. In the past, PDO has not allowed more than one reference to a bind placeholder. (Not sure if this is still the case in more recent versions of PDO.) The workaround, as demonstrated above, is to use four distinct placeholders in the statement, and supply the same value for :a1 and :a1d.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...