calculate multiple total sales of months - sql

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

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.

How to display date less that 1 month from getdate?

I have a report that shows result based on period (e.g: 1 month period, 2 month period...). I try to query and come out like this. As i would like to get record 1 month from current date
SELECT printed_serial,[name],last_active_date
FROM #Temp t
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_micard] mi on mi.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch_cuid] chcu on chcu.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch] ch on ch.ch_id = chcu.ch_id
WHERE last_active_date <= DATEADD(month, -1, getdate())
with result:
card id name last_active_date
0110 Sara jan 4 2019 4:15 pm
0111 Ara Nov 26 2013 12:22 am
but expected result :
card id name last_active_date
0110 Sara jan 4 2019 4:15 pm
You can try below - using date comparison between one month before and current date
SELECT printed_serial,[name],last_active_date
FROM #Temp t
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_micard] mi on mi.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch_cuid] chcu on chcu.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch] ch on ch.ch_id = chcu.ch_id
WHERE last_active_date >= DATEADD(month, -1, getdate())
and last_active_date <=getdate()
You are really only interested in month and year, so you can use following:
SELECT printed_serial,[name],last_active_date
FROM #Temp t
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_micard] mi on mi.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch_cuid] chcu on chcu.cu_id = t.cu_id
INNER JOIN [dbfastsconfigdataref].[dbo].[cdf_ch] ch on ch.ch_id = chcu.ch_id
WHERE MONTH(last_active_date) = MONTH(DATEADD(month, -1, getdate()))
AND YEAR(last_active_date) = YEAR(DATEADD(month, -1, getdate()))

SQL Splitting SUM Rows into Columns based on Dates

I am trying to SUM values into columns based on dates.
This is my current SQL
SELECT DISTINCT
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM') AS Month,
dbo.DR_ACCS.NAME,
SUM(dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE) AS SUMQTY,
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy') AS Year
FROM
dbo.DR_INVLINES
INNER JOIN
dbo.DR_TRANS ON dbo.DR_INVLINES.HDR_SEQNO = dbo.DR_TRANS.SEQNO
INNER JOIN
dbo.STOCK_ITEMS ON dbo.DR_INVLINES.STOCKCODE = dbo.STOCK_ITEMS.STOCKCODE
INNER JOIN
dbo.DR_ACCS ON dbo.DR_INVLINES.ACCNO = dbo.DR_ACCS.ACCNO
GROUP BY
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy'),
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM'),
dbo.STOCK_ITEMS.STOCKGROUP, dbo.DR_ACCS.NAME
HAVING
(dbo.STOCK_ITEMS.STOCKGROUP = 3)
This query returns this result set:
Mth Name SUMQTY Year
-----------------------------
Apr Company 1 1000 16
Apr Company 2 30790.4 16
Apr Company 3 1840 16
Apr Company 1 6502.9 17
Apr Company 2 2000 17
Apr Company 3 1000 17
What I am trying to achieve is
Mth Name 2016 2017
-------------------------------
Apr Company 1 800 200
Apr Company 2 15000 13000
Apr Company 3 600 569
Apr Company 1 5000 1500
Apr Company 2 2000 1986
Apr Company 3 1000 2543
Can someone please help with this..... I have been racking my brain for ages on this one ;-)
If I understand your question, you wanted to display YEAR as column,
SELECT FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM') AS Month,
dbo.DR_ACCS.NAME,
SUM(CASE WHEN YEAR(dbo.DR_INVLINES.TRANSDATE) = 2016
THEN dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE
ELSE 0
END ) AS [2016],
SUM(CASE WHEN YEAR(dbo.DR_INVLINES.TRANSDATE) = 2017
THEN dbo.DR_INVLINES.QUANTITY * dbo.STOCK_ITEMS.X_LITERAGE
ELSE 0
END ) AS [2017]
FROM dbo.DR_INVLINES
INNER JOIN dbo.DR_TRANS
ON dbo.DR_INVLINES.HDR_SEQNO = dbo.DR_TRANS.SEQNO
INNER JOIN dbo.STOCK_ITEMS
ON dbo.DR_INVLINES.STOCKCODE = dbo.STOCK_ITEMS.STOCKCODE
INNER JOIN dbo.DR_ACCS
ON dbo.DR_INVLINES.ACCNO = dbo.DR_ACCS.ACCNO
WHERE dbo.STOCK_ITEMS.STOCKGROUP = 3
GROUP BY FORMAT(dbo.DR_INVLINES.TRANSDATE, 'yy'),
FORMAT(dbo.DR_INVLINES.TRANSDATE, 'MMM'),
dbo.STOCK_ITEMS.STOCKGROUP,
dbo.DR_ACCS.NAME
Have you tried group by?
SELECT FORMAT(il.TRANSDATE, 'MMM') AS Month, a.NAME,
SUM(CASE WHEN year(il.TRANSDATE) = 2016 THEN anil.QUANTITY * si.X_LITERAGE END) AS SUMQTY_2017,
SUM(CASE WHEN year(il.TRANSDATE) = 2017 THEN anil.QUANTITY * si.X_LITERAGE END) AS SUMQTY_2016
FROM dbo.DR_INVLINES il INNER JOIN
dbo.DR_TRANS t
ON il.HDR_SEQNO = t.SEQNO INNER JOIN
dbo.STOCK_ITEMS si
ON il.STOCKCODE = si.STOCKCODE INNER JOIN
dbo.DR_ACCS a
ON il.ACCNO = a.ACCNO
WHERE si.STOCKGROUP = 3
GROUP BY FORMAT(il.TRANSDATE, 'MMM'), a.NAME;
Note the changes:
Table aliases make the query easier to write and to read.
The having clause is on an unaggregated column, so it should be a where clause.
You had an extra column in the group by.
I would recommend using datepart() or datename() over format().

Adding Year and Month to a group by sql query

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

Copy prior month value and insert into new row

Here is an example of the current table I have:
1) Table name: TotalSales
Name Year Month Sales
------ ---- ----- -----
Alfred 2011 1 100
What I want to do is create a table like this, add a new row(Prior month sales):
2) Table name: TotalSales
Name Year Month Sales Prior month sales
------ ---- ----- ----- -----------------
Alfred 2011 2 110 100
Not sure how to this, but this is what I have been working on:
SELECT Name, Year, Month, Sales, Sales as [Prior Month sales]
FROM TotalSales
WHERE
DATEPART(month, [Prior Month sales]) = DATEPART(month, DATEADD(month, -1, getdate()))
Thanks for any help
I believe this should work...you need to join to itself on name/prior month, but you have 2 test cases for prior month since year/month are stored separately.
select c.Name, c.Year, c.Month, c.Sales, p.Sales
from TotalSales c
left join TotalSales p
on c.Name = p.Name and (
(c.Month > 1 and c.Year = p.Year and c.Month = p.Month + 1)
or (c.Month = 1 and c.Year = p.Year + 1 and p.Month = 12))
To select the given data you need to join the table to itself:
SELECT
TS.name,
TS.year,
TS.month,
TS.sales,
COALESCE(TS2.sales, 0) AS prior_month_sales
FROM
TotalSales TS
LEFT OUTER JOIN TotalSales TS2 ON
TS2.name = TS.name AND
(
(TS2.year = TS.year AND TS2.month = TS.month - 1) OR
(TS.month = 1 AND TS2.month = 12 AND TS2.year = TS.year - 1)
)
The LEFT OUTER JOIN is an outer join in case they didn't have any sales the previous month (or this is their first month with the company).
Try something like this to just update the table with the values you want...
UPDATE TotalSales
SET PriorMonthSales =
(
SELECT TS.Sales
FROM TotalSales TS
WHERE
(TotalSales.Month = TS.Month + 1 AND TotalSales.Year = TS.Year)
OR
(TotalSales.Month = 1 AND TS.Month = 12 AND TS.Year = TotalSales.Year -1)
)