2013-03-10 23 views
9

Nei documenti ho potuto trovare solo un modo per creare una data da una stringa, ad es. DATE '2000-01-02'. Questo è assolutamente confuso e fastidioso. Quello che voglio invece è una funzione che richiede tre parametri, quindi potrei fare make_date(2000, 1, 2) e usare interi invece di stringhe e restituire una data (non una stringa). PostgreSQL ha una funzione così integrata?Esiste una funzione che richiede un anno, mese e giorno per creare una data in PostgreSQL?

Il motivo per cui lo sto chiedendo è perché non mi piace usare le stringhe per cose che non sono stringhe. Le date non sono archi; sono date.

La libreria client che utilizzo è HDBC-PostgreSQL per Haskell. Sto usando PostgreSQL 9.2.2.

+3

C'è una ragione per cui non è possibile utilizzare 2000 || '-' || 01 || '-' || 02? Quelli sarebbero interi, ma producono una stringa. – kainaw

+0

In futuro si prega di menzionare sempre la versione di PostgreSQL. Non penso che i downvotes siano giustificati, ma dovresti davvero spiegare di più - versione Pg, quale problema stai cercando di risolvere, la lingua e la libreria client che stai utilizzando, codice di esempio se possibile, ecc. –

risposta

7

La necessità di eseguire questa operazione in SQL di solito indica che si verificano problemi con il modello di dati in cui si memorizzano le date suddivise in campi nel DB anziché come data o campi di data/ora reali oppure si ha un grave errore di escape e SQL injection i problemi. Vedi la spiegazione di seguito.

entrambi delle seguenti risolverà il problema immediato:

CREATE OR REPLACE FUNCTION make_date(year integer, month integer, day integer) AS $$ 
SELECT year * INTERVAL '1' YEAR + month * INTERVAL '1' MONTH + day * INTERVAL '1' DAY; 
$$ LANGUAGE sql STRICT IMMUTABLE; 

o

CREATE OR REPLACE FUNCTION make_date(year integer, month integer, day integer) AS $$ 
SELECT format('%s-%s-%s', year, month, day)::date; 
$$ LANGUAGE sql STRICT IMMUTABLE; 

ma per favore, continuate a leggere.


Il fatto che si sta chiedendo questo mi fa pensare che probabilmente stai cercando di costruire SQL nell'applicazione in questo modo:

$sql = "SELECT date'" + year + '-' + month + '-' + day + "';"; 

che è generalmente pericoloso e sbagliato (sebbene probabilmente non siano direttamente sicuri se year, month e day sono tipi di dati interi). Si dovrebbe usare query parametrizzate invece se questo è quello che stai facendo per evitare SQL injection e risparmiare un sacco di seccature con la formattazione di escape e letterale. Vedi http://bobby-tables.com/.

Ecco come ci si ricerca una data utilizzando una dichiarazione con parametri in Python con psycopg2 (dal momento che non è stato specificato la lingua o strumenti):

import datetime 
import psycopg2 
conn = psycopg2.connect('') 
curs = conn.cursor() 
curs.execute('SELECT %s;', (datetime.date(2000,10,05),)) 
print repr(curs.fetchall()); 

Questo stamperà:

[(datetime.date(2000, 10, 5),)] 

cioè un array con una singola data Python al suo interno. Puoi vedere che è stato in un round trip attraverso il database e non hai mai dovuto preoccuparti del formato o della rappresentazione della data di PostgreSQL, dal momento che psycopg2 e PostgreSQL si occupano di ciò quando usi le istruzioni parametrizzate. Vedi this earlier related answer.

+0

So di Iniezione SQL e dichiarazioni preparate e non è rilevante per il mio problema. Non mi piace davvero rappresentare i valori come stringhe quando non sono stringhe, in particolare le date, poiché ci sono molti modi diversi per formattare le stringhe. –

+0

Heh, l'ultimo paragrafo ha un buon punto. Non ho notato che le librerie client supportano direttamente le date di binding. Avere un upvote –

+0

@Zoidberg Per quanto vale, in SQL un letterale come 'DATE '2012-01-01'' non è definito come una stringa, è un valore letterale di data SQL definito dallo standard. È una rappresentazione di una data come testo, ma lo è anche 'datetime.date (2012,01,01)' ed è altrettanto ben definita. In ogni caso, i collegamenti linguistici sono sicuramente la strada da percorrere. –

2

Un'altra cosa che vale la pena provare è la funzione to_date(). È simile alle associazioni sopra menzionate e non è necessario creare funzioni definite dall'utente.

http://www.postgresql.org/docs/current/static/functions-formatting.html

lo uso in questa forma:

to_Date(month::varchar ||' '|| year::varchar, 'mm YYYY') 
+0

pg-7.4 ... WTF! ?? http://www.postgresql.org/docs/9.3/static/functions-formatting.html è una versione più recente – wildplasser

17

In PostgreSQL 9.4 e maggiore è in realtà una funzione make_date(year int, month int, day int) che creerà una data.

http://www.postgresql.org/docs/9.5/static/functions-datetime.html

+0

Questa dovrebbe essere la risposta accettata –

+0

La risposta originale accettata non è aggiornata, questa è sicuramente la risposta giusta ora . –

+0

Sei un bellissimo essere umano. Se mai ci incontreremo, ti abbraccerò di tutto cuore. – Fuser97381

Problemi correlati