Consulta SQL para agrupar por día

134

Quiero enumerar todas las ventas y agrupar la suma por día.

Sales (saleID INT, amount INT, created DATETIME)

Actualización Estoy usando SQL Server 2005

mrblah
fuente
44
Debe especificar qué base de datos está utilizando, ya que las funciones de fecha son diferentes en sus dialectos SQL.
Guffa el
Mire aquí para obtener más información sobre la agrupación por día. sqlserverlearner.com/2012/group-by-day-with-examples

Respuestas:

164

si estás usando SQL Server,

dateadd(DAY,0, datediff(day,0, created)) devolverá el día creado

por ejemplo, si la venta se creó el '2009-11-02 06: 12: 55.000', dateadd(DAY,0, datediff(day,0, created))devuelva '2009-11-02 00: 00: 00.000'

select sum(amount) as total, dateadd(DAY,0, datediff(day,0, created)) as created
from sales
group by dateadd(DAY,0, datediff(day,0, created))
Anwar Chandra
fuente
fuera de la cabeza, ¿sería más eficiente diseñar de esta manera o simplemente usar DATE y agruparlo directamente?
Sinaesthetic
@Sinestésico que depende de los requisitos.
Anwar Chandra
108

Para SQL Server:

GROUP BY datepart(year,datefield), 
    datepart(month,datefield), 
    datepart(day,datefield)

o más rápido (desde Q8-Coder):

GROUP BY dateadd(DAY,0, datediff(day,0, created))

Para MySQL:

GROUP BY year(datefield), month(datefield), day(datefield)

o mejor (de Jon Bright):

GROUP BY date(datefield)

Para Oracle:

GROUP BY to_char(datefield, 'yyyy-mm-dd')

o más rápido (de IronGoofy):

GROUP BY trunc(created);

Para Informix (por Jonathan Leffler):

GROUP BY date_column
GROUP BY EXTEND(datetime_column, YEAR TO DAY)
Andomar
fuente
Gracias por enumerar todas las sintaxis diferentes
CTS_AE
43

Si estás usando MySQL:

SELECT
    DATE(created) AS saledate,
    SUM(amount)
FROM
    Sales
GROUP BY
    saledate

Si está utilizando MS SQL 2008:

SELECT
    CAST(created AS date) AS saledate,
    SUM(amount)
FROM
    Sales
GROUP BY
    CAST(created AS date)
Jon Bright
fuente
55
Me temo que estos ejemplos se
agruparán
Andomar, acabo de probar el MS SQL (después de un pequeño ajuste a la sintaxis). Felizmente agrupa por fecha aquí. No tengo tiempo para ir a probar MySQL también, pero lo uso todo el día en mi trabajo diario y estoy más o menos seguro de que también se agrupará por fecha.
Jon Bright el
@ Jon Bright: Mi comentario fue antes de una edición. El actual sigue siendo incorrecto: el tipo de fecha solo es compatible con SQL Server 2008
Andomar el
Andomar, ya que me hizo sentir inseguro, acabo de revisar el MySQL también. Funciona perfectamente y se agrupa por fecha.
Jon Bright el
Andomar, la edición hizo cero diferencia funcional para el resultado, al menos en lo que respecta a la agrupación por fecha o microsegundos. Si solo 2008 admite la fecha y hora (no lo he buscado), eso no hace que la respuesta sea incorrecta, solo se aplica a MS SQL 2008. Hay una diferencia.
Jon Bright el
7

en realidad esto depende de qué DBMS esté usando, pero en SQL regular convert(varchar,DateColumn,101)cambiará el formato DATETIME a la fecha (un día)

entonces:

SELECT 
    sum(amount) 
FROM 
    sales 
GROUP BY 
    convert(varchar,created,101)

el número magix 101es a qué formato de fecha se convierte

yopefonic
fuente
2
+1 Sí, lo que significa 101 se explica aquí msdn.microsoft.com/en-us/library/ms187928.aspx
Andomar el
7

Si está utilizando SQL Server, puede agregar tres campos calculados a su tabla:

Sales (saleID INT, amount INT, created DATETIME)

ALTER TABLE dbo.Sales
  ADD SaleYear AS YEAR(Created) PERSISTED
ALTER TABLE dbo.Sales
  ADD SaleMonth AS MONTH(Created) PERSISTED
ALTER TABLE dbo.Sales
  ADD SaleDay AS DAY(Created) PERSISTED

y ahora puede agrupar fácilmente, ordenar por etc. por día, mes o año de la venta:

SELECT SaleDay, SUM(Amount)
FROM dbo.Sales
GROUP BY SaleDay

Esos campos calculados siempre se mantendrán actualizados (cuando cambie la fecha "Creado"), son parte de su tabla, se pueden usar como los campos normales e incluso se pueden indexar (si están "PERSISTADOS" ) - gran característica que está totalmente subutilizada, en mi humilde opinión.

Bagazo

marc_s
fuente
Si de hecho! Bastante útil si tiene que ser informar sobre el día, mes, año todo el tiempo :-)
marc_s
2

Por oráculo puedes

group by trunc(created);

ya que esto trunca la fecha y hora creada a la medianoche anterior.

Otra opción es

group by to_char(created, 'DD.MM.YYYY');

que logra el mismo resultado, pero puede ser más lento ya que requiere una conversión de tipo.

Thorsten
fuente
Eso es probablemente bastante específico de Oracle, pero bastante útil. También hay un trunc (..., 'MES') para darle rápidamente el primer día del mes, etc.
Thorsten
2

Para PostgreSQL:

GROUP BY to_char(timestampfield, 'yyyy-mm-dd')

o usando el elenco:

GROUP BY timestampfield::date

si quieres velocidad, usa la segunda opción y agrega un índice:

CREATE INDEX tablename_timestampfield_date_idx ON  tablename(date(timestampfield));
Francisco Valdez
fuente
-3

usar linq

from c in Customers
group c by DbFunctions.TruncateTime(c.CreateTime) into date
orderby date.Key descending
select new  
{
    Value = date.Count().ToString(),
    Name = date.Key.ToString().Substring(0, 10)
}
liubinqiang
fuente