Guida alle date in Oracle

oracle db

Innanzitutto chiariamo un fatto troppo spesso equivocato: Oracle RDBMS, come qualsivoglia software, gestisce le informazioni sul tempo in forma numerica (rappresentazione interna), tipicamente considerando un spiazzamento da un punto temporale prefissato e stabilendo una unita di misura, avvalendosi oppure no del segno e dunque fissando il riferimento dello 0. Ma questi sono “internals” che riguardano gli sviluppatori in casa Redwood.

La struttura di memoria per conservare l’informazione varia dai 7 agli 11 bytes secondo il tipo di dato (fisso a 7 per le date, variabile per intervalli e timestamp), pertanto siamo tra 256 e 288 di possibili valori per la unita di misura minima considerata (secondi nel caso di date, frazioni di millesimi di secondo negli altri casi), ossia valori ragguardevoli.

Ma veniamo alla rappresentazione esterna di queste informazioni.

Per rappresentazione esterna intendiamo le forme in cui l’utente esprime questi valori e come il motore li presenti allo stesso utente (il meccanismo ha una certa reciprocità)

Dobbiamo considerare che l’interfaccia utente è mediata dal linguaggio SQL: questo non è un fatto marginale.
Come ogni linguaggio artificiale dobbiamo considerare simboli terminali e le varie forme di composizione, fino all’apporto fornito da “funzioni”.

Il linguaggio SQL implementato in Oracle concepisce i valori temporali come “letterali”, ossia come simboli terminali: pertanto riconosce una data come cosa differente da un char. Allo stesso modo, benché non ne introduca letterali, saprà riconoscere la diversità semantica da un valore numerico (e quindi gli operatori applicabili) per tutto ciò che è timestamp o intervalli.

Cosa vogliamo dire?
Semplicemente che esiste una sintassi, un formato con cui esprimere o in cui vengono espressi valori temporali. In particolare un formato per esprimere date.
Questo risente ovviamente della localizzazione geografica dell’interfaccia in quanto la data (più che il tempo) si esprime in modi diversi nelle varie culture.

Entrano in gioco in questo caso due variabili server (che possono essere reimpostate in sessione): NLS_DATE_FORMAT o NLS_TERRITORY
La prima consente di impostare la rappresentazione delle date esplicitamente, la seconda come conseguenza della localizzazione di tutte le informazioni che lo prevedano (date, valute, ecc)

Nell’ipotesi di un motore configurato per la lingua italiana, la stringa formata da due cifre per giorno, tre lettere per la forma abbreviata del mese e due cifre per l’anno (senza il secolo) e divise da un separatore (‘-‘ per sqlplus, ‘/’ per sqldeveloper grazie appunto a modifiche nella sessione di collegamento) rappresenta una data:

21-SET-12

Questa è la forma che otteniamo leggendo colonne di tipo data, ma se quotata, questa è anche la forma naturalecon cui impostare il valore in una colonna di tipo data:

INSERT INTO DATARIO VALUES ('21-SET-12')

Se impostiamo NLS_DATE_FORMAT in un altro modo, allora tutto potrà essere fatto con forme (ad esempio) anglosassoni per le date (nei nomi, e nella disposizione delle componenti).

Ma esistono alcuni problemi: un problema (se così li vogliamo considerare) è mostrare la completezza dell’informazione: le colonne di tipo data mantengono informazione sul secolo, sull’orario fino ai secondi, ma nessuna di queste viene mostrata nel formato standard impostato da NLS_DATE_FORMAT.Un altro problema nasce considerando il fatto che non sempre le informazioni pervengono al motore SQL nel formato utile, e tantomeno è utile estrarre dati in questo formato in quei contesti in cui occorre una maggiore attenzione alla forma (in documenti, report, interfacce utente finale, ecc).

Ed è in questi casi che entrano in gioco le funzioni SQL per la conversione (tra tipi di dati): TO_CHAR e TO_DATE.

Facciamo due esempi:

  • nel primo esempio cerchiamo di estrarre l’informazione sull’orario da una colonna di tipo data
  • nel secondo consideriamo l’ipotesi di trasformare in formato utente (o esterno) in data e una data in formato utente, ed è naturale che il tipo per lo scambio con il mondo esterno sia il più malleabile VARCHAR.

Per il primo problema usiamo la funzione TO_CHAR.
Questa converte un tipo dati (tra quelli definiti nel suo campo di azione) in una rappresentazione a caratteri attraverso una maschera di formato definita da utente e passata come argomento assieme al dato da convertire.
Abbiamo:

Formato interno -> TO_CHAR -> Formato utente specificato

Per questo esempio sfruttiamo un’altra funzione, SYSDATE, che restituisce un tipo data e viene quindi visualizzzato attraverso quanto stabilito da NLS_DATE_FORMAT. Ma attraverso la funzione TO_CHAR provvediamo a mostrare anche le componenti assenti nell’altra visualizzazione:

SELECT TO_CHAR(SYSDATE, 'MM-DD-YYYY HH24:MI:SS') "NOW" FROM DUAL;

Per il secondo problema utilizzeremo entrambe le funzioni TO_CHAR e TO_DATE e creeremo una tabella di esempio:

CREATE TABLE anag (
cod NUMBER(4),
nome VARCHAR2(20),
data_ass DATE);

In particolare la funzione TO_DATE converte una stringa che esprime una data in un tipo data. Al fine di far comprendere all’interprete SQL la data specificata occorre indicare anche il suo formato.

Formato utente -> TO_DATE -> Formato interno

Inseriamo dei dati in diversi formati utente:

INSERT INTO anag VALUES(1, 'Rossi', TO_DATE('10/01/1999', 'dd/mm/yyyy'));
INSERT INTO anag VALUES(2, 'Verdi', TO_DATE('12/02/06', 'dd/mm/yy'));
INSERT INTO anag VALUES(3, 'Gialli', TO_DATE('20100815', 'yyyymmdd'));
INSERT INTO anag VALUES(4, 'Blu', TO_DATE('101-2005', 'ddd-yyyy'));
SELECT nome, TO_CHAR(data_ass, 'dd.mm.yy') FROM anag;
SELECT nome, TO_CHAR(data_ass, 'dd-month-yy') FROM anag;
SELECT nome, TO_CHAR(data_ass, 'dd day month-yyyy') FROM anag;

Possiamo infine concludere con due osservazioni:

 

  • non è necessario utilizzare TO_DATE per impostate una data; è sufficiente essere conformi al formato dettato da NLS_DATE_FORMAT
  • se proprio occorre una conversione, e la si considera necessaria per tutte le query (in senso assoluto), è possibile reimpostare NLS_DATE_FORMAT secondo esigenze, almento a livello di sessione

 

Si imposta il formato data (nella sessione) con:

ALTER SESSION SET nls_date_format='dd.mm.yy';

Per tutti gli altri casi: usate TO_CHAR e TO_DATE a volontà.