2013-11-26 14 views
5

Sto cercando di ottenere un conteggio cumulativo di oggetti distinti in Redshift su una serie storica. La cosa semplice sarebbe usare COUNT (DISTINCT myfield) OVER (ORDER BY timefield DESC ROWS UNBOUNDED PRECEDING), ma Redshift dà un errore "Window definition non supportato".Provare a contare le entità distinte cumulative utilizzando Redshift SQL

Ad esempio, il codice riportato di seguito cerca di trovare gli utenti distinti cumulativi per ogni settimana dalla prima settimana ad oggi. Tuttavia, ottengo l'errore "Funzione finestra non supportata".

SELECT user_time.weeks_ago, 
     COUNT(distinct user_time.user_id) OVER 
      (ORDER BY weeks_ago desc ROWS UNBOUNDED PRECEDING) as count 
FROM (SELECT FLOOR(EXTRACT(DAY FROM sysdate - ev.time)/7) AS weeks_ago, 
       ev.user_id as user_id 
     FROM events as ev 
     WHERE ev.action='some_user_action') as user_time 

L'obiettivo è creare una serie storica cumulativa di utenti unici che hanno eseguito un'azione. Qualche idea su come fare questo?

risposta

3

Ha capito la risposta. Il trucco si è rivelato essere una serie di subquery nidificate, quella interna calcola il tempo della prima azione di ciascun utente. La sottoquery centrale conta le azioni totali per periodo di tempo, e la query esterna finale esegue le somme cumulative sopra la serie storica:

(SELECT engaged_per_week.week as week, 
     SUM(engaged_per_week.total) over (order by engaged_per_week.week DESC ROWS UNBOUNDED PRECEDING) as total 
FROM 
    -- COUNT OF FIRST TIME ENGAGEMENTS PER WEEK 
    (SELECT engaged.first_week AS week, 
      count(engaged.first_week) AS total 
    FROM 
     -- WEEK OF FIRST ENGAGEMENT FOR EACH USER 
     (SELECT MAX(FLOOR(EXTRACT(DAY FROM sysdate - ev.time)/7)) as first_week 
     FROM  events ev 
     WHERE ev.name='some_user_action' 
     GROUP BY ev.user_id) AS engaged 

    GROUP BY week) as engaged_per_week 
ORDER BY week DESC) as cumulative_engaged 
1

Ecco come applicarla ad un esempio citato here, più ho aggiunto un'altra riga duplicare "tabella" per "2015-01-01" per dimostrare come questo conteggia distinzioni.

L'autore dell'esempio non ha la soluzione, ma sto solo utilizzando il suo esempio.

create table public.test 
(
    "date" date, 
    item varchar(8), 
    measure int 
) 

insert into public.test 
    values 
     ('2015-01-01', 'table', 12), 
     ('2015-01-01', 'table', 120), 
     ('2015-01-01', 'chair', 51), 
     ('2015-01-01', 'lamp', 8), 
     ('2015-01-02', 'table', 17), 
     ('2015-01-02', 'chair', 72), 
     ('2015-01-02', 'lamp', 23), 
     ('2015-01-02', 'bed',  1), 
     ('2015-01-02', 'dresser', 2), 
     ('2015-01-03', 'bed',  1); 

WITH x AS (
    SELECT 
     *, 
     DENSE_RANK() 
     OVER (PARTITION BY date 
     ORDER BY item) AS dense_rank 
    FROM public.test 
) 
SELECT 
    "date", 
    item, 
    measure, 
    max(dense_rank) 
    OVER (PARTITION BY "date") 
FROM x 
ORDER BY 1; 

La sottoquery si ottiene il densa rango di ogni elemento per ogni data, quindi la query principale che si ottiene il massimo di quel denso grado per data, vale a dire, il conteggio distinto di articoli per data.

È necessario il denso rango piuttosto che il rango per contare le distinzioni.

+0

ho visto lo stesso esempio collegata che non funziona. Ma questo ha aiutato. Grazie. – systemjack

+0

cosa fai quando non vuoi restituire ogni riga con un 'select *'? Ho un caso in cui voglio contare clienti distinti per un intervallo di un mese, ma quando ordino per 'customer_id' nella partizione il set di restituzione fornisce ogni valore di rango, anche se voglio solo il massimo per il mese. – Merlin

2

Si consiglia di utilizzare DENSE_RANK invece di count (distinti):

DENSE_RANK() OVER(PARTITION BY weeks_ago ORDER BY user_time.user_id) 
Problemi correlati