2013-01-11 22 views
5

Ho una tabella postgres che assomiglia a questo:SQL somma del valore della colonna, unico per utente al giorno

id | user_id | state | created_at 

Lo stato può essere uno dei seguenti:

new, paying, paid, completing, complete, payment_failed, completion_failed 

ho bisogno di un dichiarazione che restituisce un rapporto con il seguente:

  1. somma di tutti gli stati pagati per data
  2. somma di tutti gli stati completati per data
  3. somma di tutti i nuovi, pagando, completando stati per data con una sola per utente al giorno da contare
  4. somma di tutti payment_failed, completion_failed per data con un solo per utente al giorno essere contati

Finora ho questo:

SELECT 
    DATE(created_at) AS date, 
    SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete, 
    SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid 
FROM orders 
WHERE created_at BETWEEN ? AND ? 
GROUP BY DATE(created_at) 

Una somma del in corso e stati falliti è abbastanza facile con l'aggiunta di questo al di selezione:

Ma ho problemi a capire come fare un solo con user_id al giorno in_progress e gli stati non riusciti da conteggiare.

Il motivo per cui ho bisogno di questo è di manipolare il tasso di errore nelle nostre statistiche, in quanto molti utenti che attivano un errore o un ordine incompleto continuano a innescare più che gonfia il nostro tasso di fallimento.

Grazie in anticipo.

+0

tua versione di PostgreSQL? –

+0

@IgorRomanchenko 9.1.6 –

risposta

2

Prova qualcosa di simile:

SELECT 
    DATE(created_at) AS date, 
    SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete, 
    SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid, 
    COUNT(DISTINCT CASE WHEN state IN('new','paying','completing') THEN user_id ELSE NULL END) AS in_progress, 
    COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed') THEN user_id ELSE NULL END) AS failed 
FROM orders 
WHERE created_at BETWEEN ? AND ? 
GROUP BY DATE(created_at); 

L'idea principale - COUNT (DISTINCT ...) conterà unica user_id e di solito contare NULL valori.

Dettagli: aggregate functions, 4.2.7. Aggregate Expressions

Tutta la query con stesso vale stile e semplificata CASE WHEN ...:

SELECT 
    DATE(created_at) AS date, 
    COUNT(CASE WHEN state = 'complete' THEN 1 END) AS complete, 
    COUNT(CASE WHEN state = 'paid' THEN 1 END) AS paid, 
    COUNT(DISTINCT CASE WHEN state IN('new','paying','completing') THEN user_id END) AS in_progress, 
    COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed') THEN user_id END) AS failed 
FROM orders 
WHERE created_at BETWEEN ? AND ? 
GROUP BY DATE(created_at); 
+0

Wow, questo era quasi in perfetta sincronizzazione. –

+0

@ErwinBrandstetter Sì. E le domande sono quasi identiche. :) –

+0

Accetterei anche la tua risposta se potessi, ma sembra che Erwin ti abbia battuto per un paio di minuti. Grazie per l'aiuto. –

3
SELECT created_at::date AS the_date 
     ,SUM(CASE WHEN state = 'complete' THEN 1 ELSE 0 END) AS complete 
     ,SUM(CASE WHEN state = 'paid' THEN 1 ELSE 0 END) AS paid 
     ,COUNT(DISTINCT CASE WHEN state IN('new','paying','completing') 
         THEN user_id ELSE NULL END) AS in_progress 
     ,COUNT(DISTINCT CASE WHEN state IN('payment_failed','completion_failed') 
         THEN user_id ELSE NULL END) AS failed 
FROM orders 
WHERE created_at BETWEEN ? AND ? 
GROUP BY created_at::date 

Io uso the_date come alias, dal momento che non è saggio (mentre consentito) da usare la data della parola chiave come identificatore.

Si potrebbe utilizzare una tecnica simile per complete e paid, uno è buono come l'altro c'è:

COUNT(CASE WHEN state = 'complete' THEN 1 ELSE NULL END) AS complete 
+0

Mio Dio è stato veloce! Grazie mille! –

Problemi correlati