Adding Year and Month to a group by sql query - sql

I have the following query where #BeginTime is the first day of the month and #EndTime is the last day of the month .
SET #BeginTime = RTRIM(#BeginTime) + ' 00:00:00'
SET #EndTime = RTRIM(#EndTime) + ' 23:59:59'
select C.Name , COUNT(DISTINCT D.Id) from DriverLic D
INNER JOIN Clov C WITH (NOLOCK) ON D.CId = C.CId
AND ((D.RDate < #EndTime)
AND ( D.UrDate > #BeginTime))
group by C.Name
I get an output something like this :
Name Count(D.Id)
AC 22
AB 32
CD 11
I would like to get an output something like this :
Year Month Name Count(D.id)
2013 8 AC 22
2013 8 AB 32
2013 8 CD 11
Is there a way i can achieve this ?

Yep,
SELECT Year(yourDateColumn) AS 'Year', Month(yourDateColumn) AS 'Month', C.Name, COUNT(DISTINCT D.Id)
from DriverLic D
INNER JOIN Clov C WITH (NOLOCK) ON D.CId = C.CId
--WHERE your where conditions should go here...
GROUP BY
Year(yourDateColumn), Month(yourDateColumn), C.Name

Related

Calculate Average of each month in SQL Server

I'm having two tables
Promo
ID | Name
---+---------
1 Front
2 Middle
3 Back
PromoRate
ID | Date | Rate | PromoID
---+------------+------+----------
1 2020-01-01 100 1
2 2020-01-02 200 1
3 2020-02-03 300 1
4 2020-02-01 150 2
5 2020-01-02 250 2
6 2020-03-03 350 2
7 2020-03-01 200 3
8 2020-01-02 400 3
9 2020-01-03 600 3
I want to calculate average. Something like this
Name | Avg(Jan) | Avg(Feb) | Avg(Mar)
-------+----------+----------+----------
Front 150 300 NULL
Middle 250 150 350
Back 500 NULL 200
Like pivot or something.
Please help me. Thanks in advance
What I've tried:
SELECT * FROM
(
SELECT P.ID, P.Name, AVG(Rate) AS 'AVG' FROM PromoRate PR
INNER JOIN Promo P ON P.ID = PR.ProfileID
WHERE MONTH(Date) = MONTH(GETDATE())
GROUP BY P.Name, P.ID
) M1
LEFT JOIN
(
SELECT P.ID, P.Name, AVG(Rate) AS 'AVG' FROM PromoRate PR
INNER JOIN Promo P ON P.ID = PR.ProfileID
WHERE MONTH(Date) = MONTH(GETDATE()) + 1
GROUP BY P.Name, P.ID
) M2 ON M1.ID = M2.ID
LEFT JOIN
(
SELECT P.ID, P.Name, AVG(Rate) AS 'AVG' FROM PromoRate PR
INNER JOIN Promo P ON P.ID = PR.ProfileID
WHERE MONTH(Date) = MONTH(GETDATE()) + 2
GROUP BY P.Name, P.ID
) M3 ON M2.ID = M3.ID
But it's not working as expected
You need to group on Month(Date), I'd also use DateAdd rather than month(GetDate()) + 2. You can then use the one query rather than joining on 3 queries as you're going to run into trouble when you cross the year line, or if you have multiple years. E.g. running it in November will also return the results for January that year and next year.
If this is part of a stored procedure I'd also recommend creating an #startdate and #enddate variable and setting those up first.
declare #start datetime
declare #end datetime
select #start = convert(date,GETDATE()), #end = convert(date, DATEADD(month, 2, GETDATE()))
SELECT P.ID, P.Name, AVG(Rate) AS 'AVG' FROM PromoRate PR
INNER JOIN Promo P ON P.ID = PR.ProfileID
WHERE Convert(date, Date) > #start and convert(date, date) < #end
GROUP BY P.Name, P.ID, MONTH(Date)
ETA: You also need to return your month so that you can populate your pivot table.

calculate multiple total sales of months

My desired output is shown below.I have tried to achieve it like this
*new_card_total = total sales
SELECT DATENAME(MONTH, cl.nc_timestamp) as MonthName,
COUNT(*) as new_card_qty,
ISNULL(sum(cl.nc_deposit),0) as new_card_total
FROM dbfastshosted.dbo.fh_mf_new_card_logs cl
INNER JOIN dbfastshosted.dbo.fh_sales_map m
on cl.nc_log_id = m.nc_log_id
INNER JOIN dbfastshosted.dbo.fh_sales_logs sl
on m.sales_id = sl.sales_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_terminal_user_account h
on cl.created_user_id = h.terminal_user_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_terminal t
on h.terminal_id = t.terminal_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_cuid c
on cl.cu_id = c.cu_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_card_role cr
on cr.id = c.card_role_id
INNER JOIN dbfastshosted.dbo.fh_mf_top_up_logs tl
on tl.tu_log_id = m.tu_log_id
WHERE YEAR(cl.nc_timestamp)= 2017
and cl.currency_id = 1
and (cr_log_id is null or cr_log_id = 0)
and top_up_status = 1
GROUP BY DATENAME(MONTH,cl.nc_timestamp), DATEPART(MONTH, cl.nc_timestamp)
union all
SELECT DATENAME(MONTH, cl.nc_timestamp) as MonthName,
COUNT(*) as new_card_qty,
ISNULL(sum(cl.nc_deposit),0) as new_card_total
FROM dbfastshosted.dbo.fh_mf_new_card_logs cl
INNER JOIN dbfastshosted.dbo.fh_sales_map m
on cl.nc_log_id = m.nc_log_id
INNER JOIN dbfastshosted.dbo.fh_sales_logs sl
on m.sales_id = sl.sales_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_terminal_user_account h
on cl.created_user_id = h.terminal_user_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_terminal t
on h.terminal_id = t.terminal_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_cuid c
on cl.cu_id = c.cu_id
INNER JOIN dbfastsconfigdataref.dbo.cdf_card_role cr
on cr.id = c.card_role_id
INNER JOIN dbfastshosted.dbo.fh_trans tr
on tr.trans_id = m.trans_id
WHERE YEAR(cl.nc_timestamp)= 2017
and cl.currency_id = 1
and (cr_log_id is null or cr_log_id = 0)
GROUP BY DATENAME(MONTH,cl.nc_timestamp), DATEPART(MONTH, cl.nc_timestamp)
with output :
monthname new_card_qty new_card_value
-----------------------------------------------------------
jan 100 1000
feb 200 2000
march 300 3000
march 400 5000
april 500 6000
april 500 8000
and i would like to have output like this:
monthname new_card_qty new_card_total
-----------------------------------------------------------
jan 100 1000
feb 200 2000
march 700 8000
april 1000 13000
I have tried many ways but couldnt make it.Can you please take a look on this? I really need help. Thanks!
It can be achieved by Subquery and group by as below:
SELECT MonthName, SUM(new_card_qty), SUM(new_card_value)
FROM
(SELECT DATENAME(MONTH, cl.nc_timestamp) as MonthName, COUNT(*) as new_card_qty, ISNULL(sum(cl.nc_deposit),0) as new_card_total
FROM dbfastshosted.dbo.fh_mf_new_card_logs cl ........
union all
SELECT DATENAME(MONTH, cl.nc_timestamp) as MonthName, COUNT(*) as new_card_qty, ISNULL(sum(cl.nc_deposit),0) as new_card_total
FROM dbfastshosted.dbo.fh_mf_new_card_logs cl ......) AS A
GROUP BY MonthName

Sql select sub query with count

Ok so i have 3 tables :
[AXprod].[dbo].[RMSPOSINVOICE],[AXPROD].[dbo].[discountcard] ,[IntegrationProd].[dbo].[POS_KvitoGalva]. And i want to find out when discount card was used more than once in one inventlocation and time when it was used. The table [IntegrationProd].[dbo].[POS_KvitoGalva] has these times. I use this code to get the time each card was used each day is:
sELECT a.discountcardid,count(a.discountcardid)
FROM [AXprod].[dbo].[RMSPOSINVOICE] a
inner join [AXPROD].[dbo].[discountcard] b
on a.discountcardid = b.discountcardid
inner join [IntegrationProd].[dbo].[POS_KvitoGalva] c
on a.possalesid = c.id
where a.dataareaid = 'ermi' and len(a.discountcardid) > '0' and b.dataareaid = 'ermi' and ('500' = a.inventlocationid )
and (a.invoicedate >= '2015-04-22 00:00:00.000' and a.invoicedate <= '2015-04-22 00:00:00.000')
group by a.discountcardid,a.inventlocationid,a.posnumber
having count(a.discountcardid) > '1'
And i get the following result:
DISCOUNTCARDID COUNT
123456 2
145962 2
and i have a query to find when each card was used (date and time)
SELECT a.discountcardid,a.inventlocationid,a.posnumber,year,month,day,hour,minute,c.id
FROM [AXprod].[dbo].[RMSPOSINVOICE] a
inner join [AXPROD].[dbo].[discountcard] b
on a.discountcardid = b.discountcardid
inner join [IntegrationProd].[dbo].[POS_KvitoGalva] c
on a.possalesid = c.id
where a.dataareaid = 'ermi' and len(a.discountcardid) > '0' and b.dataareaid = 'ermi' and ('500' = a.inventlocationid )
and (a.invoicedate >= '2015-04-22 00:00:00.000' and a.invoicedate <= '2015-04-22 00:00:00.000')
group by a.discountcardid,a.inventlocationid,a.posnumber,year,month,day,hour,minute,c.id
order by DISCOUNTCARDID
And i get the result:
discountcardid inventlocationid posnumber year month day hour minute id
123456 500 7 2015 4 22 12 44 6355302
123456 500 7 2015 4 22 14 24 6355302
145962 500 7 2015 4 22 13 56 6355302
145962 500 7 2015 4 22 13 24 6355302
145555 500 7 2015 4 22 12 11 5465465
The problem:
I dont want to get discount cards that were only used once so i try this:
SELECT a.discountcardid,a.inventlocationid,a.posnumber,year,month,day,hour,minute,c.id,
( sELECT count(s.discountcardid)
FROM [AXprod].[dbo].[RMSPOSINVOICE] s
inner join [AXPROD].[dbo].[discountcard] b
on s.discountcardid = b.discountcardid
inner join [IntegrationProd].[dbo].[POS_KvitoGalva] c
on s.possalesid = c.id
where s.dataareaid = 'ermi' and len(s.discountcardid) > '0' and b.dataareaid = 'ermi' and ('500' = s.inventlocationid )
and (s.invoicedate >= '2015-04-22 00:00:00.000' and s.invoicedate <= '2015-04-22 00:00:00.000') and s.DISCOUNTCARDID = a.DISCOUNTCARDID
group by s.discountcardid,s.inventlocationid,s.posnumber
having count(a.discountcardid) > '1')
FROM [AXprod].[dbo].[RMSPOSINVOICE] a
inner join [AXPROD].[dbo].[discountcard] b
on a.discountcardid = b.discountcardid
inner join [IntegrationProd].[dbo].[POS_KvitoGalva] c
on a.possalesid = c.id
where a.dataareaid = 'ermi' and len(a.discountcardid) > '0' and b.dataareaid = 'ermi' and ('500' = a.inventlocationid )
and (a.invoicedate >= '2015-04-22 00:00:00.000' and a.invoicedate <= '2015-04-22 00:00:00.000')
group by a.discountcardid,a.inventlocationid,a.posnumber,year,month,day,hour,minute,c.id
order by DISCOUNTCARDID
But all i get is the same number of values and NULL in the last field in all columns. I hope i made myself clear ;).
You should be able to call the query once and use an windowed function in order to get the count. I don't believe you can use an analytic function in the where statement so I added an additional SELECT statement in order to add the WHERE > 1 for the count.
SELECT *
FROM (SELECT
a.discountcardid,
a.inventlocationid,
a.posnumber,
year,
month,
day,
hour,
minute,
c.id,
COUNT(*) OVER (PARTITION BY a.discountcardid, a.inventlocationid, a.posnumber) AS CardCount
FROM AXprod.dbo.RMSPOSINVOICE a
JOIN AXprod.dbo.discountcard b
ON b.discountcardid = a.discountcardid
JOIN IntegrationProd.dbo.POS_KvitoGalva c
ON c.id = a.possalesid
WHERE a.dataareaid = 'ermi'
AND len(a.discountcardid) > '0'
AND b.dataareaid = 'ermi'
AND a.inventlocationid = 500
AND a.invoicedate >= '2015-04-22 00:00:00.000'
AND a.invoicedate <= '2015-04-22 00:00:00.000'
) d
WHERE d.CardCount > 1
ORDER BY d.discountcardid

Group by in subquery?

I need some help with group by in subquery. Can you help me to solve this grouping problem:
select
DATEPART(wk, oh. ExportDate) as wk,
DATEPART(dw,oh.ExportDate) as day,
ro.Name,
Pallets = sum(oh.Pallets),
Box = (select count(Number) from OrderItem where ID_OrderHead = oh.Id)
from
OrderHeadPDAEvent ohpe
left outer join OrderHead oh on oh.Id = ohpe.ID_OrderHeader
left outer join Route ro on oh.ID_Route = ro.ID
where
ID_Route = '00000000-0000-0000-0000-000000000000'
and
oh.ExportDate > dbo.GetStartOfDay('2012-08-01 14:35:00.000' )
and
oh.ExportDate < dbo.GetEndOfDay('2013-08-08 14:35:00.000')
group by
oh.ExportDate, ro.Name, oh.ID
order by
DATEPART(wk, oh. ExportDate)
And data looks like this:
26 3 Standard - Uten rute 5 49
26 3 Standard - Uten rute 2 45
26 3 Standard - Uten rute 2 38
26 3 Standard - Uten rute 1 26
26 3 Standard - Uten rute 1 64
26 3 Standard - Uten rute 2 45
26 3 Standard - Uten rute 3 64
I want to sum all rows to get them in 1 row only.
Try this one -
SELECT
DATEPART(wk, oh.ExportDate) AS wk
, DATEPART(dw, oh.ExportDate) AS day
, ro.name
, Pallets = SUM(oh.Pallets)
, Box = SUM(n)
FROM dbo.OrderHeadPDAEvent ohpe
LEFT JOIN dbo.OrderHead oh ON oh.ID = ohpe.ID_OrderHeader
LEFT JOIN dbo.[Route] ro ON oh.ID_Route = ro.ID
LEFT JOIN (
SELECT n = COUNT(number), ID_OrderHead
FROM dbo.OrderItem
GROUP BY ID_OrderHead
) t ON t.ID_OrderHead = oh.ID
WHERE ID_Route = '00000000-0000-0000-0000-000000000000'
AND oh.ExportDate BETWEEN
dbo.GetStartOfDay('2012-08-01 14:35:00.000')
AND
dbo.GetEndOfDay('2013-08-08 14:35:00.000')
GROUP BY
oh.ExportDate
, ro.name
ORDER BY wk

SQL Server : calculate monthly total sales incl empty months

I'm trying to calculate the total sales of a product in a month, but I would like it to include any "empty" months (with no sales) and only select the latest 12 months.
This is my code so far.
declare
#ProductNo int
set #ProductNo = 1234
SELECT
YEAR(o.OrderDate) as 'Year', MONTH(o.OrderDate) as 'Month', sum(Amount) as 'Units sold',[ProductNo]
FROM [OrderLine] ol
inner join [Order] o on ol.OrderNo = o.OrderNo
where ProductNo = #ProductNo
Group by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
Order by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
This returns
Year Month Units sold
2011 6 2
2011 10 1
2011 11 1
2012 2 1
But I would like it to return.
Year Month Units sold
2011 4 0
2011 5 0
2011 6 2
2011 7 0
2011 8 0
2011 9 0
2011 10 1
2011 11 1
2011 12 0
2012 1 0
2012 2 2
2012 3 0
I'm using SQL Server 2008 R2 Sp1
I've done before I know that you have calendar table. I've used master.dbo.spt_values to generate last twelve consecutive months (including current).
declare #ProductNo int
set #ProductNo = 1234
select MONTH(d.date), YEAR(d.date), isnull(t.amnt, 0) as [Units sold] from (
SELECT
YEAR(o.OrderDate) as 'Year',
MONTH(o.OrderDate) as 'Month',
sum(Amount) as amnt,
[ProductNo]
FROM [OrderLine] ol
inner join [Order] o on ol.OrderNo = o.OrderNo
where ProductNo = #ProductNo
group by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
) t
right join (
select dateadd(mm, -number, getdate()) as date
from master.dbo.spt_values
where type = 'p' and number < 12
) d on year(d.date) = t.[year] and month(d.date) = t.[month]
order by YEAR(d.date), MONTH(d.date)
Try:
;with CTE as
(select 0 months_ago union all
select months_ago - 1 months_ago from CTE where months_ago > -11),
month_list as
(select dateadd(MONTH,
months_ago,
dateadd(DAY,
1-datepart(DAY,getdate()),
cast(GETDATE() as DATE))) month_start
from cte)
SELECT YEAR(ml.start_date) as 'Year',
MONTH(ml.start_date) as 'Month',
sum(Amount) as 'Units sold',[ProductNo]
FROM month_list ml
left join [Order] o
on o.OrderDate >= ml.start_date and
o.OrderDate < dateadd(MONTH, 1, ml.start_date)
left join [OrderLine] ol
on ol.OrderNo = o.OrderNo and ProductNo = #ProductNo
Group by ProductNo, YEAR(ml.start_date), Month(ml.start_date)
Order by ProductNo, YEAR(ml.start_date), Month(ml.start_date)