online español documentacion books sql sql-server-2008 datediff

español - sql server documentation



Grupo de SQL Server por mes (7)

Tengo una tabla que tiene este esquema

ItemID UserID Year IsPaid PaymentDate Amount 1 1 2009 0 2009-11-01 300 2 1 2009 0 2009-12-01 342 3 1 2010 0 2010-01-01 243 4 1 2010 0 2010-02-01 2543 5 1 2010 0 2010-03-01 475

Intento que funcione una consulta que muestra los totales de cada mes. Hasta ahora he probado DateDiff y selecciones anidadas, pero ninguno me da lo que quiero. Esto es lo más cercano que tengo, pienso:

DECLARE @start [datetime] = 2010/4/1; SELECT ItemID, IsPaid, (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 And DateDiff(m, PaymentDate, @start) = 0 AND UserID = 100) AS "Apr", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =1 AND UserID = 100) AS "May", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =2 AND UserID = 100) AS "Jun", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =3 AND UserID = 100) AS "Jul", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =4 AND UserID = 100) AS "Aug", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =5 AND UserID = 100) AS "Sep", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =6 AND UserID = 100) AS "Oct", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =7 AND UserID = 100) AS "Nov", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =8 AND UserID = 100) AS "Dec", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =9 AND UserID = 100) AS "Jan", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =10 AND UserID = 100) AS "Feb", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =11 AND UserID = 100) AS "Mar" FROM LIVE L INNER JOIN Payments I ON I.LiveID = L.RECORD_KEY WHERE UserID = 16178

Pero obtengo nulos cuando debería obtener valores. ¿Me estoy perdiendo de algo?


Ahora su consulta está analizando explícitamente solo los pagos para el año = 2010, sin embargo, creo que quería que su Jan / Feb / Mar represente realmente el 2009. De ser así, tendrá que ajustar esto un poco para ese caso. No siga consultando los valores de suma para cada columna, solo la condición de la diferencia de fecha en meses. Pon el resto en la cláusula WHERE.

SELECT SUM( case when DateDiff(m, PaymentDate, @start) = 0 then Amount else 0 end ) AS "Apr", SUM( case when DateDiff(m, PaymentDate, @start) = 1 then Amount else 0 end ) AS "May", SUM( case when DateDiff(m, PaymentDate, @start) = 2 then Amount else 0 end ) AS "June", SUM( case when DateDiff(m, PaymentDate, @start) = 3 then Amount else 0 end ) AS "July", SUM( case when DateDiff(m, PaymentDate, @start) = 4 then Amount else 0 end ) AS "Aug", SUM( case when DateDiff(m, PaymentDate, @start) = 5 then Amount else 0 end ) AS "Sep", SUM( case when DateDiff(m, PaymentDate, @start) = 6 then Amount else 0 end ) AS "Oct", SUM( case when DateDiff(m, PaymentDate, @start) = 7 then Amount else 0 end ) AS "Nov", SUM( case when DateDiff(m, PaymentDate, @start) = 8 then Amount else 0 end ) AS "Dec", SUM( case when DateDiff(m, PaymentDate, @start) = 9 then Amount else 0 end ) AS "Jan", SUM( case when DateDiff(m, PaymentDate, @start) = 10 then Amount else 0 end ) AS "Feb", SUM( case when DateDiff(m, PaymentDate, @start) = 11 then Amount else 0 end ) AS "Mar" FROM Payments I JOIN Live L on I.LiveID = L.Record_Key WHERE Year = 2010 AND UserID = 100


Otro enfoque, que no implica agregar columnas al resultado, es simplemente poner a cero el componente del day de la fecha, por lo que 2016-07-13 y 2016-07-16 serían ambos 2016-07-01 , lo que haría ellos iguales por mes.

Si tiene un valor de date (no de datetime y datetime ), puede ponerlo en cero directamente:

SELECT DATEADD( day, 1 - DATEPART( day, [Date] ), [Date] ), COUNT(*) FROM [Table] GROUP BY DATEADD( day, 1 - DATEPART( day, [Date] ), [Date] )

Si tiene valores de datetime , deberá usar CONVERT para eliminar la porción de hora del día:

SELECT DATEADD( day, 1 - DATEPART( day, [Date] ), CONVERT( date, [Date] ) ), COUNT(*) FROM [Table] GROUP BY DATEADD( day, 1 - DATEPART( day, [Date] ), CONVERT( date, [Date] ) )


Prefiero combinar funciones DATEADD y DATEDIFF como esta:

GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Created),0)

Juntas, estas dos funciones ponen a cero el componente de fecha más pequeño que la parte de fecha especificada (es decir, MONTH en este ejemplo).

Puede cambiar el bit de fecha y datepart a YEAR , WEEK , DAY , etc., que es muy útil.

Su consulta SQL original se vería así (no puedo probarlo ya que no tengo su conjunto de datos, pero debería ponerlo en el camino correcto).

DECLARE @start [datetime] = ''2010-04-01''; SELECT ItemID, UserID, DATEADD(MONTH, DATEDIFF(MONTH, 0, Created),0) [Month], IsPaid, SUM(Amount) FROM LIVE L INNER JOIN Payments I ON I.LiveID = L.RECORD_KEY WHERE UserID = 16178 AND PaymentDate > @start

Una cosa más: la columna Month se escribe como DateTime que también es una buena ventaja si necesita procesar esos datos o asignarle un objeto .NET, por ejemplo.


Restrinja la dimensión de NVARCHAR a 7, suministrada a CONVERT para mostrar solo "AAAA-MM"

SELECT CONVERT(NVARCHAR(7),PaymentDate,120) [Month], SUM(Amount) [TotalAmount] FROM Payments GROUP BY CONVERT(NVARCHAR(7),PaymentDate,120) ORDER BY [Month]


Si necesita hacer esto con frecuencia, probablemente agregue una columna calculada PaymentMonth a la tabla:

ALTER TABLE dbo.Payments ADD PaymentMonth AS MONTH(PaymentDate) PERSISTED

Se conserva y se almacena en la tabla, por lo que no hay realmente ningún rendimiento que lo solicite. Es un valor INT de 4 bytes, por lo que la sobrecarga de espacio también es mínima.

Una vez que tenga eso, podría simplificar su consulta para que sea algo así como:

SELECT ItemID, IsPaid, (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 And PaymentMonth = 1 AND UserID = 100) AS ''Jan'', (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 And PaymentMonth = 2 AND UserID = 100) AS ''Feb'', .... and so on ..... FROM LIVE L INNER JOIN Payments I ON I.LiveID = L.RECORD_KEY WHERE UserID = 16178


DECLARE @start [datetime] = 2010/4/1;

Debiera ser...

DECLARE @start [datetime] = ''2010-04-01'';

El que tienes está dividiendo 2010 entre 4, luego con 1, luego convirtiendo a una fecha. Que es el día 57.5 desde 1900-01-01.

Pruebe SELECT @start después de su inicialización para verificar si esto es correcto.


SELECT CONVERT(NVARCHAR(10), PaymentDate, 120) [Month], SUM(Amount) [TotalAmount] FROM Payments GROUP BY CONVERT(NVARCHAR(10), PaymentDate, 120) ORDER BY [Month]

También puedes probar:

SELECT DATEPART(Year, PaymentDate) Year, DATEPART(Month, PaymentDate) Month, SUM(Amount) [TotalAmount] FROM Payments GROUP BY DATEPART(Year, PaymentDate), DATEPART(Month, PaymentDate) ORDER BY Year, Month