英文:
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 <= 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 <= nvl(?, TO_DATE)
无法进行优化,将需要完全表扫描,除非where
子句中有其他条件。
然而,对于TO_DATE <= ?
,优化器可能能够使用在TO_DATE
上的索引来进行索引的范围扫描,因此我认为第一个选项在可用索引的情况下可能更好,具体取决于情况。
> 条件可以没有等于( TO_DATE < ?)
编写第二个版本的正确方式是:
where id = ?
and (? is null or TO_DATE < ?)
然后当然需要为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 <= 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 <= ?
, 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 < ?)
You will then of course have to specify the value twice for the PreparedStatement
.
答案2
得分: 0
以下是翻译好的内容:
对于带有可选参数的查询,首先要做出以下决策:
1)是否可以对所有选项都使用一个语句。
2)最好为每个选项使用单独的语句。
在您的情况下,您有两个参数选项:
id
id
和date_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 <= ?
具有ID
和DATE_PARAM
的查询保持不变
where id=? and data_parameter <= ?
英文:
The first decision for a query with an optional parameter is as follows:
-
is it accepatable to use one statement for both / all options
-
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 <= ?
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 <= ?
Query with ID
and DATE_PARAM
remains the same
where id=? and data_parameter <= ?
Some more examples and credit for popularizing this approach can be foud here and there
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论