Pergunta

Preciso encontrar alguns registros criados em vários quartos. Por exemplo, estou procurando todos os registros criados entre o quarto trimestre de 2008 e o 1º trimestre de 2010. Tenho isso na minha cláusula onde:

...and r.record_create_date between to_date('2008 4','YYYY Q')
                                and to_date('2010 1','YYYY Q')

Mas Oracle diz: ORA-01820: format code cannot appear in date input format. o Q é um símbolo de formato de data válido, então não tenho certeza do que aconteceu. Essa é uma maneira válida de encontrar valores entre os quartos do calendário ou existe uma maneira melhor?


Também interessante e possivelmente relacionado, se eu executar isso:

select to_date('2009','YYYY') from dual;

O valor exibido no meu IDE é 2009-08-01. Eu teria esperado 2009-08-04, desde hoje é 2010-08-04.

Este:

select to_date('2009 1','YYYY Q') from dual;

Claro, falha.

(Oracle 10G)

Foi útil?

Solução

Oracle diz: ORA-01820: format code cannot appear in date input format. o Q é um símbolo de formato de data válido, então não tenho certeza do que aconteceu.

Veja a segunda coluna da Tabela 2.15 em http://download.oracle.com/docs/cd/b19306_01/server.102/b14200/sql_elements004.htm#i34948. Nem todos os elementos de formato são permitidos ao converter em datas, registros de data e hora, etc.

Eu recomendo contra o uso entre verificações de intervalo. As pessoas geralmente perdem os valores no dia final que esperam ser incluídos. Então eu traduziria:

and r.record_create_date between to_date('2008 4','YYYY Q')
                             and to_date('2010 1','YYYY Q')

Para

and to_date('2008-10-01', 'YYYY-MM-DD') <= r.record_create_date 
and record_create_date < to_date('2010-04-01', 'YYYY-MM-DD') -- < beginning of 2Q2010.

Outras dicas

Alguém fez a mesma pergunta no OTN: http://forums.oracle.com/forums/thread.jspa?threadid=1081398&tstart=255

O cerne da questão é que você pode não Especifique "q" na função to_date.

Dado que você já está especificando uma parte da data, por que não fornecer o inteira encontro? Mente também to_date('2010 1','YYYY Q') Daria a você 1º de janeiro de 2010, quando você realmente quiser 31 de março de 2010 ... de um segundo a meia -noite.

Como a relação entre os trimestres e os meses é um para muitos, não faz sentido fazer para_date ('2008 1', 'AAYYY Q'); Que data deve ser devolvida? O primeiro do trimestre, o final do trimestre, ...? (Por outro lado, converter uma data em um quarto - como_char (sysdate, 'aaaa q') faz sentido porque uma data específica existe apenas em um quarto.)

Então, se você quiser uma consulta que procure uma data que caia entre dois quartos, você terá que "rolar o seu próprio" (declarando explicitamente as datas do início/final de um quarto.)

Como nota lateral, caso alguém esteja pensando em não usar o to_date, não use coisas como: onde date_value entre 'date string1' e 'date string2' sem a função to_date. Ele pressupõe um formato de data padrão e, em determinadas situações, pode evitar índices potencialmente úteis.

Abaixo está um exemplo em que a mesma consulta pode ter um resultado diferente.

select sysdate from dual where sysdate between '1-Jan-10' and '31-Dec-10';


SYSDATE
---------
04-AUG-10

SQL> alter session set nls_date_format = 'YYYY-MM-DD';

Session altered.

SQL> select * from dual where sysdate between '1-Jan-10' and '31-Dec-10'; 

no rows selected

(Observe que, na segunda instância, nenhum erro foi retornado. Ele apenas assume 10 de janeiro de 0001 e 10 de dezembro de 0031.)

Eu acho que a melhor maneira é apenas inserir a data de início do trimestre e as datas de final de trimestre sem sequer se preocupar com o To_date. Eu acho que se você usa

between '1-Jan-10' and '31-Dec-10'

Por exemplo, então você não (no Oracle, acredito) precisa_date e não é muito mais difícil do que digitar no número do trimestre

Para calcular no Oracle no primeiro dia de um quarto e no último dia de um quarto do ano e trimestre: eu uso o fato

start_month = -2 + 3 * trimestre

last_month = 3 * trimestre

variable v_year    number

variable v_quarter number

exec :v_year     :=2017

exec :v_quarter:=4

select :v_year    as year,
       :v_quarter as quarter,
       to_date(:v_year||to_char(-2+3*:v_quarter,'fm00'),'yyyymm')        as quarter_start,
       last_day(to_date(:v_year||to_char(3*:v_quarter,'fm00')||'01 23:59:59','yyyymmdd hh24:mi:ss')) as quarter_end
from dual a;


YEAR|QUARTER|QUARTER_START      |QUARTER_END        
2017|      4|2017-10-01 00:00:00|2017-12-31 23:59:59
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top