带有IS NULL的Java准备语句

gcuhipw9  于 2023-04-28  发布在  Java
关注(0)|答案(3)|浏览(145)

假设我有一个这样的MySQL表:
VARCHAR 100|VARCHAR 100|VARCHAR 100
[ ID ] [名称] [昵称] [收藏夹_颜色]
1约翰·约翰尼·雷德
2 Eric空绿色

我想使用以下Java预处理语句选择Nickname为NULL的第2行:

statement = "SELECT * FROM my_table WHERE name = ? AND nickname = ?"

prepared = connection.prepareStatement(statement)
prepared.setString(1, "Eric")
prepared.setString(2, null)

result = prepared.executeQuery()

此查询不起作用。结果集为空。
我尝试过的另一个选择是:

statement.setNull(2,java.sql.Types.VARCHAR)

这也不起作用,结果集为空。
最后,我尝试了一个不同的SQL,但它显然是错误的,返回了太多的行(因为它不够严格):

statement = "SELECT * FROM my_table WHERE name = ? AND (nickname IS NULL) OR (nickname = ?)"

在我的例子中,这选择了太多的行。

我的问题是:如何使用Java PreparedStatement,使用MySQL 'IS NULL'选择行?

jdzmm42g

jdzmm42g1#

这是SQL数据库的一个众所周知的限制。对于大多数数据库,必须编写... WHERE field IS NULL来测试field的NULL值。... field = NULL... field = :param(其中:param是参数化查询的参数)都不匹配NULL值。
因此,唯一的解决方案是在查询中显式地写入field IS NULL。换句话说,你需要两个不同的查询,一个用于非空值(只有一个参数),另一个用于空值(和2个参数)。

statement = "SELECT * FROM my_table WHERE name = ? AND nickname = ?";
statement = "SELECT * FROM my_table WHERE name = ? AND nickname IS NULL";

你可以使用这个技巧(小心括号,如JBNizet所解释的)

statement = "SELECT * FROM my_table WHERE name = ? AND (nickname = ? OR nickname IS NULL)";

如果您仍然希望使用2个参数来查询NULL值。

pbwdgjma

pbwdgjma2#

https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_equal-to
NULL安全相等。此运算符执行与=运算符类似的相等比较,但如果两个操作数都为NULL,则返回1而不是NULL,如果一个操作数为NULL,则返回0而不是NULL。
〈=〉运算符等价于标准的SQL IS NOT DISTINCT FROM运算符。
要使null起作用,请将查询更新为:statement = "SELECT * FROM my_table WHERE name = ? AND nickname <=> ?"

pkbketx9

pkbketx93#

@John安德森,你验证了一个答案,实际上不起作用。让我解释一下。
让我们收回经过验证的比较,并关注第二个WHERE子句:

SELECT * FROM my_table
WHERE
  name = ?
  AND (nickname = ? OR nickname IS NULL)

? = 'something'的情况下,你有:

AND (nickname = 'something' OR nickname IS NULL)

-- which is equivalent to:
AND (NULL OR nickname IS NULL)

-- which is equivalent to:
AND (nickname IS NULL)

所以你总是得到nickname为NULL的行,不管?的值是什么(当?实际上不是NULL时的副作用)。实际上,在?不为NULL的情况下,您总是会得到NULL行和您要查找的行。

下面是一种实际操作技巧的方法(亲自测试):

SELECT * FROM my_table
WHERE
  name = ?
  AND ((? IS NULL AND nickname IS NULL) OR (? IS NOT NULL AND nickname = ?))

2个主要病例的详细信息:

  1. ?NULL
AND ((NULL IS NULL AND nickname IS NULL) OR (NULL IS NOT NULL AND nickname = ?))

-- which is equivalent to:
AND ((TRUE AND nickname IS NULL) OR (FALSE AND nickname = NULL))

-- which is equivalent to:
AND ((nickname IS NULL) OR (FALSE AND NULL))

-- which is equivalent to:
AND ((nickname IS NULL) OR (FALSE))

-- which is equivalent to:
AND (nickname IS NULL)

所以你得到的就是nickname为NULL的行。

  1. ? = 'something'
AND (('something' IS NULL AND nickname IS NULL) OR ('something' IS NOT NULL AND nickname = 'something'))

-- which is equivalent to:
AND ((FALSE AND nickname IS NULL) OR (TRUE AND nickname = 'something'))

-- which is equivalent to:
AND (FALSE OR (nickname = 'something'))

-- which is equivalent to:
AND (nickname = 'something')

所以你确切地得到了nickname = 'something'的行。

相关问题