Oracle Java – 向预处理语句添加可选日期参数

huangapple go评论92阅读模式
英文:

Oracle Java - Add optional date parameter to Prepared statement

问题

我想在预处理语句中添加可选的"todate"参数。

一种方法是添加一个占位符来表示可选参数,然后在执行之前进行替换:

  where id=? OPTIONAL_SECTION 

例如,OPTIONAL_SECTION 可以设置为 TO_DATE <= sysdate -1

一种更好且正确的方法是将可选参数与处理空值绑定:

where id=? and TO_DATE <= nvl(?, TO_DATE)

有没有更好的方法来处理可选的日期参数?
特别是因为条件可以是不等于的(TO_DATE < ?)

  • 这只是一个最简示例,id 不是主键(实际上是外键),SQL 将返回多条记录。
英文:

I want to add optional "todate" parameter to Prepared statement

One way is to add a placeholder for optional parameter(s) and replace it before execute

  where id=? OPTIONAL_SECTION 

For example OPTIONAL_SECTION will be set to TO_DATE <=sysdate -1

A better and correct way is to bind optional parameter with handling null

where id=? and TO_DATE &lt;= nvl(?, TO_DATE)

Is there a better way to handle optional date parameter?
Specially because condition can be without equal ( TO_DATE < ?)

  • This is a minimal example, Id isn't a primary key (actually it's a foreign key), SQL return multiple records 

答案1

得分: 1

> 一个更好且正确的方法是将可选参数与处理空值绑定

这未必更好或更正确。这是另一种方式,但这是否“更好和(更)正确”存在很大争议。

SQL查询优化器通常在任何?参数值可知之前运行,因此TO_DATE &lt;= nvl(?, TO_DATE)无法进行优化,将需要完全表扫描,除非where子句中有其他条件。

然而,对于TO_DATE &lt;= ?,优化器可能能够使用在TO_DATE上的索引来进行索引的范围扫描,因此我认为第一个选项在可用索引的情况下可能更好,具体取决于情况。


> 条件可以没有等于( TO_DATE < ?)

编写第二个版本的正确方式是:

where id = ?
  and (? is null or TO_DATE &lt; ?)

然后当然需要为PreparedStatement指定两次值。

英文:

> A better and correct way is to bind optional parameter with handling null

That is not necessarily better or more correct. It is a different way, but it's very debatable if it is "better and (more) correct".

SQL Query optimizers generally run before any ? argument values are known, so a TO_DATE &lt;= nvl(?, TO_DATE) cannot be optimized and will require a full table scan, barring any other conditions in the where clause.

However with a TO_DATE &lt;= ?, the optimizer may be able to use an index on TO_DATE to do a ranged scan of the index, so I'd argue that the first option is potentially better, depending on available indexes.


> condition can be without equal ( TO_DATE < ?)

The correct way to write the second version is:

where id = ?
  and (? is null or TO_DATE &lt; ?)

You will then of course have to specify the value twice for the PreparedStatement.

答案2

得分: 0

以下是翻译好的内容:

对于带有可选参数的查询,首先要做出以下决策:

1)是否可以对所有选项都使用一个语句

2)最好为每个选项使用单独的语句

在您的情况下,您有两个参数选项:

id

iddate_parameter

从命名来看,我认为ID是表的主键,因此它只返回一行,并且将是执行计划中的驱动程序 - 简单的索引访问

date_parameter只会导致查询选择性地不返回任何行

在这种情况下,您可以安全地使用决策1)- 一个查询适用于两个选项

但是在另一种解释中,ID是一个具有大量行的外键,而date_parameter用于仅返回少量最近的行。

在这种情况下,决策1)即OR查询将失败。执行计划针对返回大量数据进行了优化,因此您将等待很长时间才能获取少量行。

因此,在这种情况下,只有决策2)提供了一个性能良好的解决方案。简短的答案是基于传递的参数动态生成两个查询

where id=?

where id=? and data_parameter <= ?

使用这种方法的技术问题是,查询具有不同数量的绑定变量,这使得setXXX变得复杂。

为了避免这个问题,您可以使用1=1 or技巧,a)使所有查询中的绑定变量数量相等,并且b)消除不必要的部分。

仅查询ID的查询生成如下:

where id=? and 1=1 or data_parameter <= ?

具有IDDATE_PARAM的查询保持不变

where id=? and data_parameter <= ?

关于这种方法的更多示例和推广来自这里那里

英文:

The first decision for a query with an optional parameter is as follows:

  1. is it accepatable to use one statement for both / all options

  2. it is prefered to use a separate statament for each option

In your case you have two parameter options:

id

id and date_parameter

From the naming, I'd argue, that ID is a primary key of the table, so it returns one row only and will be the driver in the execution plan - simple index access.

The date_parameter could only cause that the query return optionally no row

In this case you may safely use the decision 1) - one query for both option will be fine

But in other interpretation, the ID is a foreign key with tons of rows and the date_parameter is used to return only a small number of recent rows.

In this case the decision 1) aka OR query will fail badly. The execution plan is optimized on the case returning mass data, so you will wait ages to get few rows.

So in this case only decision 2) provides a performant solution. The short answer is to dynamically generate two queries based on the parameter passed

where id=? 

where id=? and data_parameter &lt;= ?

The technical problem with this approach is, that the queries have a different number of bind variables which makes the setXXX complicated.

To avoid this problem you can use the 1=1 or trick, that a) makes the number of the bind variable equal in all queries* and b) eliminates the not necessary onces.

Query for ID only is generated as

where id=? and 1=1 or data_parameter &lt;= ?

Query with IDand DATE_PARAM remains the same

where id=? and data_parameter &lt;= ? 

Some more examples and credit for popularizing this approach can be foud here and there

huangapple
  • 本文由 发表于 2020年4月5日 12:46:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/61038191.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定