Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Ignore o parâmetro de intervalo de datas na cláusula where quando o parâmetro não for inserido


Você tem duas possibilidades para abordar os parâmetros de entrada opcionais.

O mais simples maneira é usar SQL estático e fornecer default valor para os parâmetros ausentes, para que você obtenha todas as correspondências.

Aqui você simplesmente define os limites para a DATE mínima e máxima possível.
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')

Quanto mais avançado way foi popularizado por Tom Kyte e é baseado no uso de SQL dinâmico.

Se os parâmetros forem fornecidos , você gera SQL normal com o BETWEEN predicado :
select * 
from customer
where customer_id = $P{CLIENT_ID}
and datetrx between $P{DATE_START} and $P{DATE_END}

Caso o parâmetro esteja faltando (ou seja, NULL é passado) você gera um SQL diferente como mostrado abaixo.
select * 
from customer
where customer_id = $P{CLIENT_ID}
and (1=1 or datetrx between $P{DATE_START} and $P{DATE_END})

Observe que

1) o número de variáveis ​​de ligação é o mesmo em ambas as variantes da consulta, o que é importante, pois você pode usar setXXXX idêntico declarações

2) devido ao atalho 1 = 1 or é o between predicado ignorado, ou seja, todas as datas são consideradas.

Qual ​​opção deve ser usada?

Bem, para consultas simples, haverá uma pequena diferença, mas para consultas complexas com várias opções de parâmetros ausentes e dados grandes, a abordagem SQL dinâmica é preferida .

A razão é que, usando SQL estático, você usa a mesma instrução para consultas mais diferentes - aqui uma para acesso com intervalo de dados e um para acesso sem intervalo de dados.

A opção dinâmica produz SQL diferente para cada acesso.

Você pode vê-lo nos planos de execução:

Acesso com intervalo de datas
-------------------------------------------------------------------------------
| 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)

Acesso sem intervalo de dados
------------------------------------------------------------------------------
| 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)

Ambas as instruções produzem um plano de execução diferente, que é otimizado para o parâmetro de entrada. Na opção estática, o uso deve compartilhar o mesmo plano de execução para todas as entradas que possam causar problemas.