2012-06-12 16 views
5

Estoy tratando de calcular el número de usuarios, acumulativamente para la base de datos dellstore2. En cuanto a respuestas aquí y en otros foros, he utilizado estetotales mensuales acumulativos y Postgresql

select 
date_trunc('month',orderdate), 
sum(count(distinct(customerid))) 
    over (order by date_trunc('month',orderdate)) 
from orders group by date_trunc('month',orderdate) 

Esto devuelve

2004-01-01 00:00:00.0 979 
2004-02-01 00:00:00.0 1,952 
2004-03-01 00:00:00.0 2,922 
2004-04-01 00:00:00.0 3,898 
2004-05-01 00:00:00.0 4,873 
2004-06-01 00:00:00.0 5,846 
2004-07-01 00:00:00.0 6,827 
2004-08-01 00:00:00.0 7,799 
2004-09-01 00:00:00.0 8,765 
2004-10-01 00:00:00.0 9,745 
2004-11-01 00:00:00.0 10,710 
2004-12-01 00:00:00.0 11,681 

Cada mes es

979 
973 
970 
976 
975 
973 
981 
972 
966 
980 
965 
971 

Parece ser total fina, mirando a los primeros pocos artículos. Pero cuando me encontré

select count(distinct(customerid)) from orders 

para toda la cosa, me sale

8996 

que no está de acuerdo con el último elemento de la primera salida de 11.681. Supongo que el cálculo anterior no puede determinar la singularidad a lo largo de los meses. ¿Cuál es la forma más rápida de realizar este cálculo, preferiblemente sin utilizar autouniones?

+1

¿Algunos clientes compraron cosas más de una vez? En diferentes meses? –

+0

@ NikolaMarkovinović tiene razón al respecto, usted debe hacer ese comentario una respuesta ... –

+0

@pOcHa Od svih gradova, moj omiljeni Niš .... :-) –

Respuesta

7

En lugar de seleccionar directamente de pedidos, se puede utilizar una subconsulta de esta manera:

SELECT OrderDate, 
     SUM(COUNT(DISTINCT customerid)) OVER (ORDER BY OrderDate) 
FROM ( SELECT CustomerID, 
        DATE_TRUNC('MONTH', MIN(OrderDate)) AS OrderDate 
      FROM Orders 
      GROUP BY CustomerID 
     ) AS Orders 
GROUP BY OrderDate 

Creo que esto iba a funcionar como se requiere.

http://sqlfiddle.com/#!1/7a8cc/1

EDITAR

Si todavía necesitan ambos métodos (es decir, distinto y total acumulado) se puede usar esto:

SELECT OrderDate, 
     COUNT(DISTINCT CustomerID) AS MonthTotal, 
     SUM(COUNT(DISTINCT customerid)) OVER (ORDER BY OrderDate) AS CumulativeTotal, 
     SUM(COUNT(DISTINCT CASE WHEN OrderNumber = 1 THEN customerid END)) OVER (ORDER BY OrderDate) AS CumulativeDistinctTotal 
FROM ( SELECT CustomerID, 
        OrderDate, 
        ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY OrderDate) AS OrderNumber 
      FROM Orders 
     ) AS Orders 
GROUP BY OrderDate 

Ejemplo aquí:

http://sqlfiddle.com/#!1/7a8cc/10

+2

+1 - Muy bonito pensamiento batman. – MatBailie

+0

que de hecho funciona, y no tengo idea de por qué. :) intentaré entenderlo. Gracias. – user423805

+1

El primero funciona porque en lugar de usar 'COUNT (DISTINCT CustomerID)' para eliminar los duplicados, los duplicados se eliminan agrupando el conjunto de datos que se cuenta para que obtenga los mismos resultados sin 'DISTINCT' en el recuento. El segundo es básicamente el mismo que tu consulta original con una columna 'ROW_NUMBER' adicional añadida al conjunto, esto se usa para identificar el primer pedido para cada cliente, por lo que es posible contar todos los pedidos y clientes distintos. – GarethD