Funzione to_date Oracle con quarto formato
-
25-09-2019 - |
Domanda
Ho bisogno di trovare alcuni record creati in una serie di trimestri. Per esempio, io sto cercando tutti i record creati tra il 4 ° trimestre del 2008 e il 1 ° trimestre del 2010. Ho questo nel mio DOVE clausola:
...and r.record_create_date between to_date('2008 4','YYYY Q')
and to_date('2010 1','YYYY Q')
ma Oracle dice: ORA-01820: format code cannot appear in date input format
. Il Q
è un simbolo formato di data valida, quindi non sono sicuro di quello che è successo. E 'questo anche un modo valido per trovare i valori tra quartieri di calendario, o c'è un modo migliore?
Interessante anche, e forse in relazione, se eseguo questo:
select to_date('2009','YYYY') from dual;
Il valore visualizzato nel mio IDE è 2009-08-01
. Mi sarei aspettato 2009-08-04
, dal momento che oggi è 2010-08-04
.
Questa:
select to_date('2009 1','YYYY Q') from dual;
Naturalmente, non riesce.
(Oracle 10g)
Soluzione
Oracle dice: ORA-01820: format code cannot appear in date input format
. Il Q
è un simbolo formato di data valida, quindi non sono sicuro di quello che è successo.
Vedere la seconda colonna della tabella 2.15 a http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34948 . Non tutti gli elementi di formato sono consentiti durante la conversione in date, timestamp, ecc.
mi raccomando contro l'uso tra i controlli per intervallo di date. La gente spesso mancherà valori entro il giorno finale che l'aspettano di essere inclusi. Quindi mi sento di tradurre:
and r.record_create_date between to_date('2008 4','YYYY Q')
and to_date('2010 1','YYYY Q')
Per
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.
Altri suggerimenti
Qualcuno ha chiesto la stessa domanda su OTN: http: // forum .oracle.com / forum / thread.jspa? threadID = 1081398 & Tinizio = 255
Il nocciolo della questione è che si può non specificare "Q" nella funzione TO_DATE.
Dato che si sta già specificare una parte della data, perché non fornire il intero Data? Mente anche che to_date('2010 1','YYYY Q')
darebbe 1 gennaio 2010 quando si vuole veramente 31 MARZO 2010 ... in un secondo a mezzanotte.
Poiché la relazione tra quarti di mesi è uno-a-molti, non ha senso fare TO_DATE ( '2008 1', 'aaaa q'); quale data deve essere restituito? Il primo del trimestre, la fine del trimestre, ...? (Al contrario, la conversione di una data ad un quarto -. Come TO_CHAR (SYSDATE, 'aaaa q') senso perché una data specifica esiste solo in un quarto)
Quindi, se si vuole una query che cerca una data che cade tra due trimestri, si dovrà "rolll il proprio" (indicando esplicitamente le date di inizio / fine di un trimestre.)
Come nota a margine, nel caso qualcuno sta prendendo in considerazione non usare TO_DATE prega di non utilizzare le cose come: DOVE date_value TRA 'data string1' e 'data stringa2' senza la funzione TO_DATE. Assume un formato predefinito di data e in certe situazioni può evitare indici potenzialmente utili complessivamente.
Di seguito è un esempio in cui la stessa query può avere un risultato diverso.
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
(Si noti che nel secondo caso si restituisce alcun errore. Esso assume che 10 gen 0001 e testi 10th, 0031).
Penso che il modo migliore è quello basta inserire la data di inizio e di fine quarto trimestre senza nemmeno preoccuparsi con to_date. Penso che se si utilizza
between '1-Jan-10' and '31-Dec-10'
per esempio, allora non (in Oracle credo) necessità to_date e non è molto più difficile che la digitazione del numero trimestre
Per calcolare in Oracle il primo giorno di un trimestre e l'ultimo giorno di un quarto dal anno e trimestre: Io uso il fatto
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