【问题标题】:Alternative for COALESCE when all its parameters is nullCOALESCE 的所有参数都为空时的替代方案
【发布时间】:2019-04-22 20:06:27
【问题描述】:

我正在开发一个 Web 应用程序(java-maven 项目),但我使用的查询存在问题。我的网络应用程序的 UI 有 2 个搜索字段:PTTID。 用户需要填写至少一个字段才能进行搜索。所以这两个字段都可以为空,但不能同时为空。 之前,我只有一个字段:PTR,它显示了一个大小为 52 的结果数组。(如果 我执行select * from users where ptr='smthing')。之后我添加了ID 字段并更新了我的查询如下:

我在我的网络服务中执行这个查询:

String query= "SELECT t.ptr, t.id ";
        query+= "FROM users t ";
        query+= "WHERE t.ptr = COALESCE(?, t.ptr) AND " ;
        query+= "t.id = COALESCE(?, t.id) ";

并借助 Prepared Statement 设置字段。

现在如果 ptr 字段已填充,但 id 字段在 UI 上留空(可以是 null 或空字符串)并且用户进行搜索,结果数组大小变为 30。我与数据库进行了比较 它不会获取ID 为空的行。所以coalesce 的两个参数 (?, t.ptr) 都为空时,我不需要它。 我该如何解决这个问题,有什么建议吗?

【问题讨论】:

  • 什么数据库?甲骨文?
  • 顺便说一下,PL/SQL Developer 不是 Oracle 产品,PL/SQL 也不是查询语言。

标签: java sql oracle plsql


【解决方案1】:

我认为你想要的逻辑是:

WHERE (t.ptr = ? OR ? IS NULL) AND 
      (t.id = ? OR ? IS NULL)

我建议使用命名参数,这样您就不必将它们传递两次。

【讨论】:

  • 谢谢 :) 一个问题:我们如何为“?”设置参数这里。在旧版本中,我将它们设置为 PreparedStatement ps = conn.prepareStatement(query); ps.setString(1, obj.getPTT()); ps.setString(1, obj.getID());我问这个是因为现在我得到“java.sql.SQLException: Missing IN or OUT parameter at index”
  • @csel 。 . .这个版本有四个参数而不是两个,所以你需要包含所有四个参数。
【解决方案2】:

检查此声明:

String query= "SELECT t.ptr, t.id ";
query+= "FROM users t ";
query+= "WHERE (t.ptr = ? OR 1 = ?)" 
query+= " AND " ;
query+= "(t.id = ? OR 1 = ?)";

您会看到t.idt.ptr 中的每一个都有一个对应参数。
总共将有 4 个参数。
您说t.idt.ptr至少有1 个 具有有效值,因此有2 种情况:

[1] @987654326 @ 和 t.ptr 都有有效值。

对于您传递0 的两个对应参数,查询变为:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0) AND (t.id = valueid OR 1 = 0)"
在WHERE部分:
t.ptr = valueptr OR 1 = 0等价于t.ptr = valueptr
t.id = valueid OR 1 = 0等价于t.id = valueid
查询最终变为:
"SELECT t.ptr, t.id FROM users t WHERE t.ptr = valueptr AND t.id = valueid"

[2] from t.id or t.ptr 只有一个有有效值,假设这是t.ptr .

对于t.ptr 的对应项,您传递0,对于t.id,您传递-1(或任何其他不存在的值),对于t.id 的对应项,您传递1,查询变为:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0) AND (t.id = -1 OR 1 = 1)"
在 WHERE 部分:
t.ptr = valueptr OR 1 = 0 等价于t.ptr = valueptr,而
t.id = -1 OR 1 = 1 等价于true,因为1 = 1 始终是true
查询最终变为:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0)"
相当于:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr)"

(在只有 t.id 具有有效值的情况下,如果 t.id 传递 0,则为 t.ptr1 传递无效值,如果 t.id 传递 0。)

也许它看起来很复杂,但它很有效,并且可以扩展到超过 2 列。

【讨论】:

    【解决方案3】:

    Oracle 对此有构建功能。但是很难理解如何使用它。

    lnnvl(a = b) = true if (a != b ) or ( a = null ) or (b = null)

    你的情况

    WHERE lnnvl(t.ptr != ? ) AND lnnvl( t.id != ?)
    

    LNNVL

    【讨论】:

    • 我有 2 个问题。我现在按照你说的那样使用,它带来了空字段,这是我想要的东西之一,但是例如让我们说 ptr 输入为“abcdef”并且 id 留空它会带来所有带有空 ptr 和 ptr='abcdef' 的记录从数据库。第二件事是我如何将它与 "BETWEEN" 一起使用?我想在 lnnvl 中添加 "query += "t.date BETWEEN COALESCE(?, t.date) AND COALESCE(?,t.date) AND ";" 类似这样的内容。
    • ++ 我认为 lnnvl 将所有空 ptr 值也带入是正常行为。我只想带上所有 ptr 值为 'abcdef' 的记录(如果用户提交了 ptr 字段的值)。但它没有带来具有空 ID 和 ptr='abcdef' 的记录
    猜你喜欢
    • 2018-07-19
    • 1970-01-01
    • 2017-07-15
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-30
    • 2017-07-18
    相关资源
    最近更新 更多