【问题标题】:Ignore the date range parameter in the where clause when parameter is not entered不输入参数时忽略where子句中的日期范围参数
【发布时间】:2019-06-26 14:58:38
【问题描述】:

不输入参数时忽略where子句中的日期范围参数。对于我的日期范围,我使用的是 Between。

这些参数是从 jasper 报告中输入的

SELECT * 
  from customer 
 where client_id = $P{CLIENT_ID} 
   AND (Account_id = CASE WHEN $P{Account_ID}>0 
                          THEN $P{Account_ID} 
                          ELSE Account_ID END 
        OR Account_ID IS NULL ) 
   AND datetrx BETWEEN $P{DATE_START} AND $P{DATE_END} 

如果未输入日期,则报告应包含任何日期的记录,因为未输入日期范围

【问题讨论】:

  • SQL 文本是静态的还是可以根据输入参数生成动态 SQL?
  • 您可以使用Oracle 的内置函数nvl,假设未输入的参数值与null 相同。你熟悉那个功能吗?如果DATE_START 为空,则使用另一个Oracle 内置函数to_date 创建一个迄今为止的日期,使datetrx 列的所有值都比它更新。
  • 感谢@MarmiteBomber 的回复,是的,sql 是动态的,这些参数是从碧玉报告中输入的
  • 感谢您的回复@Abra 不,我对 nvl 不熟悉,最近才开始使用 oracle。在我的情况下,datetrx 永远不是空值,但我可能不会输入参数并且仍然想将所有内容都带上任何日期。现在,当我使用上述内容时,如果我不输入日期参数​​,我会得到一个空白报告。

标签: oracle


【解决方案1】:

您有两种方法来处理可选输入参数。

更简单的方式是使用静态 SQL 并为缺失的参数提供 default 值,以便获得所有匹配项。

在这里,您只需将边界设置为可能的最小和最大 DATE。

select * 
from customer
where customer_id = $P{CLIENT_ID}
and datetrx between nvl($P{DATE_START},date'1900-01-01') 
                and nvl($P{DATE_END},date'2200-01-01')

高级的方式由Tom Kyte推广,基于使用动态SQL。

如果提供了参数,您将生成带有BETWEEN 谓词的普通SQL

select * 
from customer
where customer_id = $P{CLIENT_ID}
and datetrx between $P{DATE_START} and $P{DATE_END}

如果参数丢失(即NULL被传递),您将生成一个不同的SQL,如下所示。

select * 
from customer
where customer_id = $P{CLIENT_ID}
and (1=1 or datetrx between $P{DATE_START} and $P{DATE_END})

请注意,

1) 两个查询变体中绑定变量的数量相同,这很重要,因为您可以使用相同的 setXXXX 语句

2) 由于 shortcut 1 = 1 orbetween 谓词被忽略,即考虑所有日期。

应该使用哪个选项?

对于简单的查询会有很小的差异,但是对于具有多个缺少参数和大数据选项的复杂查询,首选动态 SQL 方法

原因是,使用静态 SQL,您对更多不同的查询使用相同的语句 - 这里一个用于访问 with 数据范围,另一个用于访问 没有 数据范围。

动态选项为每次访问生成不同的 SQL。

你可以在execution plans看到它:

访问日期范围

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |     1 |    22 |     1   (0)| 00:00:01 |
|*  1 |  FILTER           |           |       |       |            |          |
|*  2 |   INDEX RANGE SCAN| CUST_IDX1 |     1 |    22 |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(TO_DATE(:1)<=TO_DATE(:2))
   2 - access("CUSTOMER_ID"=1 AND "DATETRX">=:1 AND "DATETRX"<=:2)

无数据范围的访问

------------------------------------------------------------------------------
| Id  | Operation        | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |           |     1 |    22 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| CUST_IDX1 |     1 |    22 |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("CUSTOMER_ID"=1)

两个语句产生不同的执行计划,针对输入参数进行了优化。在静态选项中,对于所有可能导致问题的输入,必须共享相同的执行计划

【讨论】:

    猜你喜欢
    • 2015-02-24
    • 2020-12-28
    • 1970-01-01
    • 2019-07-15
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多