SQL last 15 months of sales grouped by customer - sql

I would like to output in sql a table that contains the monthly sales per customer. Each column should correspond to another month.
First column should be current month example my sql columns are:
customer
invoicedate
sales
Original table looks like this:
+------------+------------+---------+
| Customer | invdate | sales |
+------------+------------+---------+
| Best Buy | 03-12-2019 | 433 |
| Walmart | 03-15-2019 | 543 |
| Home Depot | 12-12-2018 | 32 |
+------------+------------+---------+
Desired Output:
+------------+----------+--------+--------+--------+--------+----------+
| Customer | March 19 | Feb 19 | Jan 19 | Dec 18 | Nov 18 | Oct 18 |
+------------+----------+--------+--------+--------+--------+----------+
| Home Depot | 100 | 300 | 244 | 32 | 322 | 43 |
| Walmart | 543 | 222 | 234 | 12 | 234 | 34 |
| Bestbuy | 433 | 323 | 323 | 23 | 433 | 34 |
+------------+----------+--------+--------+--------+--------+----------+

You can use group by, sum, and case to good effect, like this:
select
customer,
sum(case when year(invdate) = year(getdate) and month(invdate) = month(getdate()) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,1,getdate))
and month(invdate) = month(dateadd(m,1,getdate())) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,2,getdate))
and month(invdate) = month(dateadd(m,2,getdate())) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,3,getdate))
and month(invdate) = month(dateadd(m,3,getdate())) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,4,getdate))
and month(invdate) = month(dateadd(m,4,getdate())) then sales else o end),
sum(case when year(invdate) = year(dateadd(m,5,getdate))
and month(invdate) = month(dateadd(m,5,getdate())) then sales else o end)
from tableyoudidnotgivethenameof
group by customer

Related

How to display results for each year in a new column in SQL

How can we show result of each year between the condition dates in separate column?
Can we show '0' for "EQ_no" filed which is not in "Jobs" table.
select A.EQ_no,A.Serial_no,sum(J.total_cost)Total_Cost,YEAR(Job_Date) as Job_Year
from Equipment A
left OUTER JOIN Jobs J ON J.EQ_no=A.EQ_no
where J.Job_Date BETWEEN '01/01/2018' AND DATEADD(DAY, 1, '12/31/2020')
group by A.EQ_no,A.Serial_no,YEAR(Job_Date)
Table : Jobs
+-------+------------+------------+
| EQ_no | Job_Date | Total_Cost |
+-------+------------+------------+
| 1006 | 01/30/2017 | 250 |
| 1006 | 01/31/2018 | 350 |
| 1006 | 01/01/2019 | 150 |
| 1006 | 02/01/2019 | 322 |
| 1006 | 05/05/2019 | 450 |
| 1006 | 02/02/2020 | 500 |
| 1006 | 02/03/2021 | 1212 |
| 29198 | 02/04/2017 | 3000 |
| 29198 | 02/05/2018 | 250 |
+-------+------------+------------+
Table : Equipment
+-------+-----------+
| EQ_no | Serial no |
+-------+-----------+
| 1006 | MDRSC12 |
| 29198 | FDRSC13 |
| 6218 | REAFC14 |
+-------+-----------+
Result
+-------+-----------+------+------+------+
| EQ_no | Serial no | 2018 | 2019 | 2020 |
+-------+-----------+------+------+------+
| 1006 | MDRSC12 | 350 | 922 | 500 |
| 29198 | FDRSC13 | 250 | 0 | 0 |
| 6218 | REAFC14 | 0 | 0 | 0 |
+-------+-----------+------+------+------+
SQL Version : 2014
Add CASE statement inside the SUM aggregate function.
And use ISNULL function to replace the Null values by '0'
select A.EQ_no,A.Serial_no,ISNULL(MAX(J.EQ_no),0) AS Job_Eq_No
,ISNULL(sum(CASE WHEN YEAR(Job_Date) = 2018 THEN J.total_cost END),0)[2018]
,ISNULL(sum(CASE WHEN YEAR(Job_Date) = 2019 THEN J.total_cost END),0)[2019]
,ISNULL(sum(CASE WHEN YEAR(Job_Date) = 2012 THEN J.total_cost END),0)[2020]
from Equipment A
left OUTER JOIN Jobs J ON J.EQ_no=A.EQ_no
where J.Job_Date BETWEEN '01/01/2018' AND DATEADD(DAY, 1, '12/31/2020')
group by A.EQ_no,A.Serial_no
First, a left join is not needed for your query.
Second, you should be using proper date constants.
Third, you can do this with conditional aggregation:
select e.EQ_no, e.Serial_no,
sum(case when year(j.job_date) = 2018 then J.total_cost else 0 end) as total_cost_2018,
sum(case when year(j.job_date) = 2019 then J.total_cost else 0 end) as total_cost_2019,
sum(case when year(j.job_date) = 2020 then J.total_cost else 90 end) as total_cost_2020
from Equipment e join
Jobs j
on J.EQ_no = e.EQ_no
where j.job_date >= '2018-01-01' and
j.job_date < '2021-01-01'
group by e.EQ_no, e.Serial_no;
Also note that this fixes the where clause so the case is using the same column. Your sample data doesn't have a column named datetime_open.

Generating Aging Report

I need to generate an aging report using the below sample data from tblAccount.
+---------+----------+---------------+-------------------+---------------------+-------------+-----------+---------+
| Loan ID | Account | Name | Amortization Date | Amortized Principal | Paid Amount | Date Paid | Balance |
+---------+----------+---------------+-------------------+---------------------+-------------+-----------+---------+
| 2 | A0007787 | JIMMY NEUTRON | 3/9/2020 | 3823.53 | 3823.53 | 3/9/2020 | 0 |
| 2 | A0007787 | JIMMY NEUTRON | 4/9/2020 | 3823.53 | 500 | 3/9/2020 | 3323.53 |
| 2 | A0007787 | JIMMY NEUTRON | 5/9/2020 | 3823.53 | 0 | NULL | 3823.53 |
+---------+----------+---------------+-------------------+---------------------+-------------+-----------+---------+
Zero (0) paid amount and NULL Date Paid means that the amortized principal is not yet paid. Below is my desired output for specific Aging dates.
Aging A - Aging on March 12 Payment has been made on March 12 for March 9 schedule
+---------+----------+---------------+------------+------------+---------+---------+-------+-------+-----
+---------+----------+---------------+------------+------------+---------+---------+-------+-------+-------+---------------+
| Loan ID | Account | Name | Due | Payment | Balance | Current | 30 | 60 | 90 | 120 and Above |
+---------+----------+---------------+------------+------------+---------+---------+-------+-------+-------+---------------+
| 2 | A0007787 | JIMMY NEUTRON | 3,823.53 | 3,823.53 | 0 | - | - | - | - | - |
+---------+----------+---------------+------------+------------+---------+---------+-------+-------+-------+---------------+
Aging B - May 10 500.00 payment has been made on April 9 for April 9 schedule
+---------+----------+---------------+------------+----------+------------+------------+-------+-------+-------+-----------------+
| Loan ID | Account | Name | Due | Payment | Balance | Current | 30 | 60 | 90 | 120 and Above |
+---------+----------+---------------+------------+----------+------------+------------+-------+-------+-------+-----------------+
| 2 | A0007787 | JIMMY NEUTRON | 3,823.53 | 500.00 | 3,323.53 | 3,323.53 | - | - | - | - |
+---------+----------+---------------+------------+----------+------------+------------+-------+-------+-------+-----------------+
Aging C - June 10 There is remaining balance for April 9 schedule and no payment made for May 9
schdeule
+---------+----------+---------------+------------+---------+------------+-----------+------------+------------+-------+-----------------+
| Loan ID | Account | Name | Due | Payment | Balance | Current | 30 | 60 | 90 | 120 and Above |
+---------+----------+---------------+------------+---------+------------+-----------+------------+------------+-------+-----------------+
| 2 | A0007787 | JIMMY NEUTRON | 7,147.06 | 500 | 7,147.06 | - | 3,823.53 | 3,323.53 | - | - |
+---------+----------+---------------+------------+---------+------------+-----------+------------+------------+-------+-----------------+
I have looked and tried suggested solutions here, made tweeks, but it seems that it does not fit to what I wanted to produce.
Currently, I have this kind of Stored Procedure:
INSERT INTO #Aging (
Loan, ID, Account, Name, AmortizationSchedule, AmortizedPrincipal, PaidAmount, DatePaid, Balance)
SELECT Loan, ID, Account, Name, AmortizationSchedule, AmortizedPrincipal, PaidAmount, DatePaid, Balance
FROM tblAccount
Select DISTINCT Loan, ID, Account, Name, AmortizationSchedule, AmortizedPrincipal, PaidAmount, DatePaid, Balance
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) < 1 then balance else 0 end) as [Current],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) between 1 and 30 then balance else 0 end) as [DueTo30],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) between 31 and 60 then balance else 0 end) as [DueTo60],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) between 61 and 90 then balance else 0 end) as [DueTo90],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) between 91 and 120 then balance else 0 end) as [DueTo120],
(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf )) > 120 then balance else 0 end) as [Over120]
from #Aging where balance<>0.00
order by Account
But it gives the following result,
+---------+----------+---------------+-------------+------------+-------------+-----------+-------+-------------+----+-----------------+
| Loan ID | Account | Name | Due | Payment | Balance | Current | 30 | 60 | 90 | 120 and Above |
+---------+----------+---------------+-------------+------------+-------------+-----------+-------+-------------+----+-----------------+
| 2 | A0007787 | JIMMY NEUTRON | 90,000.00 | 8,647.06 | 14,294.12 | - | - | 14,294.12 | 0 | 0 |
+---------+----------+---------------+-------------+------------+-------------+-----------+-------+-------------+----+-----------------+
It seems that it duplicate the value of due, payment and balance on the number of amortization schedule which is three (March, April, May)
Hoping for a positive response. TIA!
Your query gives the correct results once group by and sum used. Am I missing something?
Select DISTINCT [Loan ID], Account, [Name]
,sum(AmortizedPrincipal) Due, sum(PaidAmount) Payment, sum(Balance) Balance,
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) < 1 then balance else 0 end) as [Current],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) between 1 and 30 then balance else 0 end) as [DueTo30],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) between 31 and 60 then balance else 0 end) as [DueTo60],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) between 61 and 90 then balance else 0 end) as [DueTo90],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) between 91 and 120 then balance else 0 end) as [DueTo120],
sum(case when DATEDIFF(day,convert(date,AmortizationSchedule),convert(date,#DateAsOf)) > 120 then balance else 0 end) as [Over120]
from #Aging where balance<>0.00
GROUP BY [Loan ID], Account, [Name]
order by Account
Please check the db<>fiddle here.

Sql Query issue and error regarding groupby cause

I am trying to calculate the total number of Projects in every year. and also how many projects are active, how many of them are canceled.
I tried to group by cause for PRojects dates so we have a total number of project in every year but I am not sure where to start and what to do
Select ts.Id as projectid ,
--a.ParentObjectId,
ts.RequestName as ProjectDates,
ts.Type,
ts.Category,
ts.SubType,
ts.status as projectstatus,
Count (ts.ReceptionDate),
cast (ts.ReceptionDate as Date) as ReceptionDate,
from [rpt].[TransmissionServicesRpt] ts
left join [dbo].[AuditHistory] a on a.ParentObjectId = ts.Id
Left join [dbo].[User] u on a.CreatedById = u.id
Group by ts.id, ts.ReceptionDate
+ -------------+--------+-----------+------------+----------+-----------------+
| New Projects | Active | Cancelled | Terminated | Inactive | Carried Forward |
+ -------------+--------+-----------+------------+----------+-----------------+
| 2013 | 32 | 45 | 4 | 11 | 30 |
| 2014 | 45 | 75 | 17 | 14 | 44 |
| 2015 | 46 | 90 | 25 | 21 | 44 |
| 2016 | 30 | 74 | 27 | 10 | 37 |
| 2017 | 82 | 119 | 11 | 26 | 82 |
| 2018 | 86 | 168 | 29 | 24 | 115 |
| 2019 | 23 | 138 | 9 | 4 | 125 |
+ -------------+--------+-----------+------------+----------+-----------------+
You want one result row per year. So group by year. You get it via YEAR or DATEPART. Then count conditionally:
select
year(receptiondate) as year,
count(*) as total,
count(case when status = 'Active' then 1 end) as active,
count(case when status = 'Cancelled' then 1 end) as cancelled,
count(case when status = 'Terminated' then 1 end) as terminated,
count(case when status = 'Inactive' then 1 end) as inactive,
count(case when status = 'Carried Forward' then 1 end) as carried_forward
from rpt.transmissionservicesrpt
group by year(receptiondate)
order by year(receptiondate);

sql Group by columns to the same row without join

I have grouped sales from a sales view with sales below using
Select id, name, Count(*) as [Sales], product, amount
from vwSales
Group by
id,name, product, amount
ID | Name | Sales | Product | Amount
1 | Bob | 4 | Fridge | 40
1 | Bob | 12 | Washer | 120
2 | Anne | 5 | Fridge | 50
2 | Anne | 4 | Washer | 40
Is it possible to group these in to one row without using a join? So table looks something like
ID | Name | Fridge Sales | fridge Amt | Washer sales | washer amt
1 | Bob | 4 | 40 | 12 | 120
2 | Anne | 5 | 50 | 4 | 40
You can do conditional aggregation :
select id, name,
sum(case when Product = 'Fridge' then 1 else 0 end) as [Fridge Sales],
sum(case when Product = 'Fridge' then Amount else 0 end) as [fridge Amt],
sum(case when Product = 'Washer' then 1 else 0 end) as [Washer Sales],
sum(case when Product = 'Washer' then Amount else 0 end) as [Washer Amt]
from vwSales
Group by id, name;

SQL column sum and difference

my table, I want to create three columns in single-column, reprinted now.
id | date | type | total
------ | ------ | ------ | -----
1 | 01.10.2016| Paypal | 50
2 | 03.10.2016| credit | 40
3 | 05.10.2016| Cash | 50
4 | 06.10.2016| payment| 100
5 | 07.10.2016| Cash | 20
6 | 15.10.2016| Skrill | 10
7 | 18.10.2016| payment| 20
8 | 19.10.2016| Paypal | 10
9 | 19.10.2016| payment| 20
10 | 22.10.2016| Cash | 40
11 | 23.10.2016| Skrill | 10
my table, I want to create three columns in single-column, reprinted now.
SELECT id,date,type,total
(select (
sum(case when type="Paypal" then total else 0 end)+
sum(case when type="credit" then total else 0 end))+
sum(case when type="Cash" then total else 0 end) ) as receiv,
(Select(
sum(case when type="payment" then total else 0 end)) AS payment,
(Select sum(receiv -payment) FROM totals t2
WHERE (t2.date <= t1.date) and (t2.id <= t1.id) order by t1.date) AS remainder
FROM totals t1
group by date, type
order by id,date
--
The following query for the sql code?
Type = "Paypal, credit, Cash" sums "receiv" sums and Type = "payment" sums will be added to the "remainder" column.
id | date | type | receiv| payment| remainder
------ | ------ | ------ | ------| ------ | ------
1 | 01.10.2016| Paypal | 50 | 0 | 50
2 | 03.10.2016| credit | 40 | 0 | 90
3 | 05.10.2016| Cash | 50 | 0 | 140
4 | 06.10.2016| payment| 0 | 100 | 40
5 | 07.10.2016| Cash | 20 | 0 | 60
6 | 15.10.2016| Skrill | 10 | 0 | 70
7 | 18.10.2016| payment| 0 | 20 | 50
8 | 19.10.2016| Paypal | 10 | 0 | 60
9 | 19.10.2016| payment| 0 | 20 | 40
10 | 22.10.2016| Cash | 40 | 0 | 80
11 | 23.10.2016| Skrill | 10 | 0 | 90
Running total is easier in other databases which have analytical functions. In MySQL, you can do this with a correlated sub-query.
select id,dt,type,
case when type <> 'payment' then total else 0 end receiv,
case when type = 'payment' then total else 0 end payment,
case when type <> 'payment' then total else 0 end
- case when type = 'payment' then total else 0 end
+ coalesce((select sum(case when type <> 'payment' then total else 0 end)
- sum(case when type = 'payment' then total else 0 end)
from yourtable where id < y.id),0)
from yourtable y
Sample Demo