SQL: Cómo agrupar por año personalizado
Pregunta
Por simplicidades, inventaré un ejemplo similar al que tengo:
Digamos que un db tiene una tabla de pedidos con un campo OrderDate y un campo Company. Luego hay una tabla de compañías y cada registro tiene un YearEndingDate (que significa que el año termina en esa fecha cada año, por ejemplo, 6/6).
Necesito sumar todos los pedidos de cada año.
Supongo que tendría que ser algo como esto, pero no puedo entenderlo:
SELECT SUM(orderValue),
CASE WHEN orderDate <= YearEndingDate THEN DatePart(year, orderDate)
CASE WHEN orderDate > YearEndingDate THEN DatePart(year, orderDate) + 1
END as Year
FROM Orders
INNER JOIN Company ON Company.companyID = Order.companyID
GROUP By Company, Year
¿Alguna idea?
Solución
No estoy seguro de qué RDMS está utilizando, pero esto debería ser el truco. Las partes datepart y dateadd son específicas de tsql, pero supongo que tendría acceso a funciones similares en cualquier plataforma que esté utilizando. El caso en donde determina qué valor de año utilizar.
Respuesta:
select c.companyid
,yearendingdate + '/' + convert(varchar, datepart(yy, dateadd(yy,1,o.orderdate))) as yearending
,sum(ordervalue) as numberoforders
from @orders o
join @companies c
on o.companyid = c.companyid
where orderdate between case when (cast(yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate)) as datetime) >= o.orderdate)
then yearendingdate + '/' + convert(varchar, datepart(yy, dateadd(yy,-1,o.orderdate)))
else yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate))
end
and
case when (cast(yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate)) as datetime) >= o.orderdate)
then yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate))
else yearendingdate + '/' + convert(varchar, datepart(yy, dateadd(yy,1,o.orderdate)))
end
group by c.companyid, o.orderdate, yearendingdate
Código para resolver el problema:
declare @orders table (OrderDate datetime
,CompanyID varchar(20)
,OrderValue int)
insert into @orders
values (getdate(),'MS',2)
insert into @orders
values (DateAdd(year, -1, getdate()),'MS',3)
insert into @orders
values (DateAdd(year, -1, getdate()),'MS',1)
insert into @orders
values (DateAdd(year, 1, getdate()),'MS',4)
insert into @orders
values (DateAdd(year, 1, getdate()),'Blizzard',2)
insert into @orders
values (getdate(),'MS',11)
declare @companies table (CompanyID varchar(20)
,YearEndingDate varchar(20))
insert into @companies
values ('MS', '05/6')
insert into @companies
values ('Blizzard', '07/01')
select c.companyid
,o.orderdate
,yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate)) as sameyear
,yearendingdate + '/' + convert(varchar, datepart(yy, dateadd(yy,1,o.orderdate))) as plusyear
,yearendingdate + '/' + convert(varchar, datepart(yy, dateadd(yy,-1,o.orderdate))) as minusyear
from @orders o
join @companies c
on o.companyid = c.companyid
select c.companyid
,yearendingdate + '/' + convert(varchar, datepart(yy, dateadd(yy,1,o.orderdate))) as yearending
,sum(ordervalue) as numberoforders
from @orders o
join @companies c
on o.companyid = c.companyid
where orderdate between case when (cast(yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate)) as datetime) >= o.orderdate)
then yearendingdate + '/' + convert(varchar, datepart(yy, dateadd(yy,-1,o.orderdate)))
else yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate))
end
and
case when (cast(yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate)) as datetime) >= o.orderdate)
then yearendingdate + '/' + convert(varchar, datepart(yy, o.orderdate))
else yearendingdate + '/' + convert(varchar, datepart(yy, dateadd(yy,1,o.orderdate)))
end
group by c.companyid, o.orderdate, yearendingdate