2012-05-11 9 views
9

Tengo un conjunto de datos de direcciones de correo electrónico y las fechas en que esas direcciones de correo electrónico se agregaron a una tabla. Puede haber varias entradas de una dirección de correo electrónico para varias fechas diferentes. Por ejemplo, si tengo el conjunto de datos a continuación. Me gustaría obtener la fecha y el recuento de distintos correos electrónicos que tenemos entre dicha fecha y 3 días atrás.Consulta para el recuento de valores distintos en un intervalo de fechas variable

Date | email 
-------+---------------- 
1/1/12 | [email protected] 
1/1/12 | [email protected] 
1/1/12 | [email protected] 
1/2/12 | [email protected] 
1/2/12 | [email protected] 
1/3/12 | [email protected] 
1/4/12 | [email protected] 
1/5/12 | [email protected] 
1/5/12 | [email protected] 
1/6/12 | [email protected] 
1/6/12 | [email protected] 
1/6/12 | [email protected] 

conjunto de resultados se vería algo como esto si usamos un período de fecha de 3

date | count(distinct email) 
-------+------ 
1/1/12 | 3 
1/2/12 | 3 
1/3/12 | 3 
1/4/12 | 3 
1/5/12 | 2 
1/6/12 | 2 

puedo conseguir un recuento distinto de un intervalo de fechas utilizando la consulta a continuación, pero que buscan obtener un recuento de un rango por día, así que no tengo que actualizar manualmente el rango para cientos de fechas.

select test.date, count(distinct test.email) 
from test_table as test 
where test.date between '2012-01-01' and '2012-05-08' 
group by test.date; 

Ayuda es apreciada.

Respuesta

0

en el servidor SQL:

`select test.date, count(distinct test.email) from test_table as test where convert(date,test.date) between '2012-01-01' and '2012-05-08' group by test.date` 

esperanza esto ayuda.

+1

Esto se denomina PostgreSQL. No función 'convert()' aquí. (Bueno, hay una función 'convert()', pero es para convertir codificaciones, no tipos de datos como en SQL server.) Además, se desalientan las firmas, tu estilo en la parte inferior derecha se ocupa de eso. Ver [aquí] (http://meta.stackexchange.com/questions/5029/are-taglines-signatures-disallowed) o [aquí] (http://stackoverflow.com/faq#signatures). –

11

caso de prueba:

CREATE TEMP TABLE tbl (day date, email text); 
INSERT INTO tbl VALUES 
('2012-01-01', '[email protected]') 
,('2012-01-01', '[email protected]') 
,('2012-01-01', '[email protected]') 
,('2012-01-02', '[email protected]') 
,('2012-01-02', '[email protected]') 
,('2012-01-03', '[email protected]') 
,('2012-01-04', '[email protected]') 
,('2012-01-05', '[email protected]') 
,('2012-01-05', '[email protected]') 
,('2012-01-06', '[email protected]') 
,('2012-01-06', '[email protected]') 
,('2012-01-06', '[email protected]`'); 

consultas - Devuelve solo día en que existe una entrada en tbl:

SELECT day 
    ,(SELECT count(DISTINCT email) 
     FROM tbl 
     WHERE day BETWEEN t.day - 2 AND t.day -- period of 3 days 
    ) AS dist_emails 
FROM tbl t 
WHERE day BETWEEN '2012-01-01' AND '2012-01-06' 
GROUP BY 1 
ORDER BY 1; 

O - volver todos los días en el rango especificado, incluso si no hay filas para el día:

SELECT day 
    ,(SELECT count(DISTINCT email) 
     FROM tbl 
     WHERE day BETWEEN g.day - 2 AND g.day 
    ) AS dist_emails 
FROM (SELECT generate_series('2012-01-01'::date 
          , '2012-01-06'::date, '1d')::date) AS g(day) 

Resul t:

day  | dist_emails 
-----------+------------ 
2012-01-01 | 3 
2012-01-02 | 3 
2012-01-03 | 3 
2012-01-04 | 3 
2012-01-05 | 1 
2012-01-06 | 2 

Esto sonaba como un trabajo para window functions al principio, pero que no encontrar una manera de definir el marco de la ventana adecuada. Además, per documentation:

funciones de la ventana de agregados, a diferencia de las funciones de agregado normales, no permiten DISTINCT o ORDER BY para ser utilizado dentro de la lista de argumentos de la función.

Así que lo resolví con subconsultas correlacionadas en su lugar. Creo que esa es la forma más inteligente.

Cambié el nombre de la columna de fecha al day, porque es una mala práctica usar nombres de tipo como identificadores.

Por cierto, "entre dicha fecha y 3 días" sería un período de días. Tu definición es contradictoria allí.

un poco más corto, pero más lento por sólo unos pocos días:

SELECT day, count(DISTINCT email) AS dist_emails 
FROM (SELECT generate_series('2013-01-01'::date 
          , '2013-01-06'::date, '1d')::date) AS g(day) 
LEFT JOIN tbl t ON t.day BETWEEN g.day - 2 AND g.day 
GROUP BY 1 
ORDER BY 1; 
+0

excelente respuesta, gracias @ErwinBrandstetter – Sean

0

En lugar de especificar la fecha, siempre se puede utilizar una función dateadd:

test.date > dateadd(dd,-7,getdate()) 
+1

No hay "dateadd()" en PostgreSQL. –

0

Un ejemplo de ventana distinta deslizante cuenta:

SELECT b.day, count(DISTINCT a.user_id) 
from glip_production.presences_1d a, 
(SELECT distinct(day), TIMESTAMPADD(day,-6, day) dt_start 
    from glip_production.presences_1d t1) b 
where a.day >= b.dt_start and a.day <= b.day and b.day > '2017-11-01' 
group by b.day 
Cuestiones relacionadas