SQL Query to sum by month - sql

i have the two tables, Payment Table and Person Table, a person por month can have more than one payment, so i want so sum all "amount" fields from a parson per month and per year, if there is no payment the result should be 0 and ID of the person should appear in the month.
i am almost there, but in my curreny query the data displayed is all payments per person and not the sum. how can o het this?
current results are like this (see october) i need to sum below 3 payments and olny show one line of october 2013:
My Table
MonthNr---MonthAbr---Amount---PersonID---YearAmount
1---JAN---0---2---2013
2---FEB---0---2---2013
3---MAR---0---2---2013
4---APR---0---2---2013
5---MAY---0---2---2013
6---JUN---0---2---2013
7---JUL---0---2---2013
8---AUG---0---2---2013
9---SEP---0---2---2013
10---OCT---64,74---2---2013
10---OCT---73,66---2---2013
10---OCT---24,3---2---2013
11---NOV---24,3---2---2013
12----DEC----0---2----2013
My query:
SELECT
months.monthno as MonthNr,
CAST(CASE WHEN CAST(months.monthno AS int) =1 THEN 'JAN'
WHEN CAST(months.monthno AS int) =2 THEN 'FEB'
WHEN CAST(months.monthno AS int) =3 THEN 'MAR'
WHEN CAST(months.monthno AS int) =4 THEN 'APR'
WHEN CAST(months.monthno AS int) =5 THEN 'MAY'
WHEN CAST(months.monthno AS int) =6 THEN 'JUN'
WHEN CAST(months.monthno AS int) =7 THEN 'JUL'
WHEN CAST(months.monthno AS int) =8 THEN 'AUG'
WHEN CAST(months.monthno AS int) =9 THEN 'SEP'
WHEN CAST(months.monthno AS int) =10 THEN 'OCT'
WHEN CAST(months.monthno AS int) =11 THEN 'NOV'
WHEN CAST(months.monthno AS int) =12 THEN 'DEC'
ELSE
''
END AS nvarchar) as MonthAbr,
Amount = isnull(sum(o.Amount),0),
c.IDPerson as PersonID,
isnull(year(o.Date ),2013) as YearAmount
FROM
Person c
cross join
(select number monthNo from master..spt_values where type='p' and number between 1 and 12) months
full join Payments o
ON o.IDPerson = c.IDPerson
AND month(o.Date ) = months.monthNo
where c.IDPerson = 2
GROUP BY
months.monthno, c.IDPerson ,o.Date
ORDER BY
months.monthno, c.IDPerson
can anyone help me?
thanks in advance.

Since you are using the isnull function on o.date I assume this means there are nulls in this column. If so, you need to account for this within your group by clause, e.g. "group by months.monthno, c.idperson, isnull(year(o.date),2013)".

You shouldn't group by o.Date, but only by the month of the date, which you already have included as months.monthno.

Why dont you simplify it:
select
months.monthno as MonthNr
,case when monthno='1' then 'JAN'
when monthno='2' then 'FEB'
end as MonthAbr
isnull(year(o.Date ),2013) as YearAmount
,sum(Amount)
from PERSONS c
left join Payments o ON o.IDPerson = c.IDPerson
left join
(select number monthNo from master..spt_values where type='p' and number between 1 and 12) months on months.number= select month(o.Date)
group by months.monthno, o.date

Related

SUM and Grouping by date and material

Still learning SQL forgive me.
I have 3 tables. a material table, a material_req table and a material_trans table. I want to group by material and then group columns by year.
so it would be [material, 2019, 2018, 2017, 2016, total (total being the total qty used for each material.
I have tried to place the date in the select statement, and grouped by the date also. but then the returned result is a lot of the same material with a lot of dates. I only need the year. maybe try the same and return just the year?
SELECT material_req.Material
-- , Material_Trans_Date
, SUM(-1 * material_trans.Quantity) AS 'TOTAL'
,Standard_Cost
FROM
Material_Req inner join Material_Trans
ON
Material_Req.Material_Req = Material_Trans.Material_Req
LEFt JOIN Material
ON
Material.Material = Material_Req.Material
WHERE
material_trans.Material_Trans_Date between '20180101' AND GETDATE()
-- Material_Trans_Date between '20180101' AND '20181231'
-- Material_Trans_Date between '20170101' AND '20171231'
-- Material_Trans_Date between '20160101' AND '20161231'
GROUP BY
material_req.Material ,Standard_Cost
ORDER BY
Material_Req.Material, Standard_Cost
expected results should by grouped by material, 2019, 2018, 2017,2016, Standard_Cost. the years column will have the sum of qty for each material for that year.
results look like this current_results
If you are using SQL Server then you might try this:
SELECT material_req.Material
, SUM(CASE WHEN DATEPART(YEAR, Material_Trans_Date) = '2019' THEN material_trans.Quantity ELSE 0 END) [2019 TOTAL]
, SUM(CASE WHEN DATEPART(YEAR, Material_Trans_Date) = '2018' THEN material_trans.Quantity ELSE 0 END) [2018 TOTAL]
,Standard_Cost
FROM
Material_Req inner join Material_Trans
ON
Material_Req.Material_Req = Material_Trans.Material_Req
LEFt JOIN Material
ON
Material.Material = Material_Req.Material
WHERE
material_trans.Material_Trans_Date between '20180101' AND GETDATE()
GROUP BY
material_req.Material ,Standard_Cost
ORDER BY
Material_Req.Material, Standard_Cost

SQL Rollup to Sum Totals of a Grouped Table

I have a table that is grouped by 'Group Type'. What I need is for the last row to display the sum of the values in the above rows in the Total row.
Below is the code currently but I am not sure how to sum multiple fields at once.
Actual
Expected Result
Do I need to add another CASE statement to
select
CASE when GROUP_TYPE is null then 'Total' ELSE GROUP_TYPE END as 'Group Type',
Sum_Amount, TotalER, [Discount Report]
from
(select GROUP_TYPE, sum(cast(AMOUNT as float)) as Sum_Amount FROM [dbo].[a]
where cast(ACTIVITY_DATE as date) between #startdate and #enddate
group by GROUP_TYPE with rollup) a
left join
(select [Charge Group] , sum(cast([Earned Revenue] as float)) as
TotalER, sum(cast(Discount as float)) as 'Discount Report'
from [dbo].[er] group by [Charge Group]) er
on
a.GROUP_TYPE = er.[Charge Group]
select sum(cast([er] as float)) from [dbo].[er]
I would do a union all before the aggregation. This makes it easier to specify the multiple aggregation sets:
select coalesce(group_type, 'Total') as group_type, -- the easy way
sum(amount) as sum_amount, sum(er) as totaler, sum(discount) as discount
from ((select group_type, cast(amount as float) as Amount, 0 as ER, 0 as discount
from [dbo].a
where cast(ACTIVITY_DATE as date) between #startdate and #enddate
) union all
(select [Charge Group], 0, cast([Earned Revenue] as float) as er, cast(Discount as float)
from [dbo].er
where cast(ACTIVITY_DATE as date) between #startdate and #enddate
)
) aer
group by grouping sets ( (group_type), () );

SQL: Showing all the products for each month even when

I'm trying to create a query that shows me all the products for each month, but I get stuck, because if a product its not sold in a certain month it wont appear, and I want to pass the value from month to month progressive.
For example like in this Picture:
You can see that for February I've got OLD and ORD, but because in March and April there was no Products sold I can't see, neither in May because there was no OLD product sold it wont appear. I want for each month to have all products, even if in the beginning its null.
Something like that:
February 2015:
0-OIR, 2-OLD, 2-ORD
March 2015:0-OIR, 2-OLD, 2-ORD
April 2015:0-OIR, 2-OLD, 2-ORD
May 2015:1-OIR,2-OLD, 5-ORD
June 2015: 1-OIR, 2-OLD, 7-ORD
and so on this table goes until current date
The column from the left its Cumulative summing per product and in the right between year and month its Cumulative summing for all products.
The query looks like this.
select
sum(a.count) over (partition by [Product Name] ORDER BY Year,Month) as 'Sum Per Product'
,a.[Product Name]
,a.month
,a.Year
,sum(a.Count) OVER (ORDER BY Year,Month) as 'Cumulative Sum of all products'
,
case
a.Month
when 1 then 'January'
when 2 then 'February'
when 3 then 'March'
when 4 then 'April'
when 5 then 'May'
when 6 then 'June'
when 7 then 'July'
when 8 then 'August'
when 9 then 'September'
when 10 then 'October'
when 11 then 'November'
when 12 then 'December'
end [months]
from (
SELECT
count(COALESCE(p.ShortName + ' ' ,'No Product')) as 'Count'
,COALESCE(p.ShortName + ' ' ,'No Product') as 'Product Name'
,MONTH(m.CreatedDatetime) AS 'Month'
,YEAR(m.CreatedDatetime) AS 'Year'
FROM Request r
LEFT JOIN Contact c on r.ContactId = c.ID
LEFT JOIN Machine m on r.machineId = m.ID
LEFT JOIN MachineStatus ms on m.active = ms.ID
join machineProduct mp on m.Id=mp.MachineId
LEFT JOIN RequestProduct rp on r.ID = rp.RequestId
LEFT JOIN ProductVersion pv on pv.ID = rp.ProductVersionId
LEFT JOIN Product p on pv.ProductId = p.ID
WHERE
m.statusid in (1,2)
GROUP BY COALESCE(p.ShortName + ' ' ,'No Product'), YEAR(m.CreatedDatetime),MONTH(m.CreatedDatetime)) a
group by Month,Year,a.count,a.[Product Name]
Order by a.Year,a.Month,a.[Product Name],[months]
EDIT:
I've created a temporary table that looks like this but how can I connect it to my main query to retrieve the info from Temp Table + The 2 Columns Cumulative summing per product and Cumulative summing for all products.
The query looks like this
`Declare #temp table
(id int
,name nvarchar(40)
,yeari int
,monthi int
)
-
Insert into #temp (id,name,yeari,monthi) (Select prd.id,prd.shortname,mac.yeari,mac.monthi
from (Select id,shortname from Product where Product.Active=1) prd
cross join (select distinct year(m.createddatetime) as yeari
,month(m.createddatetime) as monthi
FROM machine m
) mac)`
The Output looks like this:
How can I connect them?

How to merge sql query with union into one query

I would like to get the results of the below query with just one query not by using union.
My query is as below
I am generating a SSRS chart this query, so need to merge the query into one and get a proper result as shown in table 2
select
res.Count, res.Month, res.status, res.SortOrder
from
(SELECT
count(analysis_complete_date) as Count,
DATENAME(month, analysis_complete_date) AS Month,
DATEPART(month, analysis_complete_date) AS SortOrder,
'Analysis' as status
FROM
SCN_Part_Details AS parts
WHERE
analysis_complete_date BETWEEN '2014-01-01' AND '2014-12-11'
GROUP BY
DATENAME(month, analysis_complete_date),
DATEPART(month, analysis_complete_date)
union
SELECT
count(Act_Supp_Negotiation_Date) as Count,
DATENAME(month, Act_Supp_Negotiation_Date) AS Month,
DATEPART(month, Act_Supp_Negotiation_Date) AS SortOrder,
'Negotiated' as status
FROM
SCN_Part_Details AS parts
WHERE
Act_Supp_Negotiation_Date BETWEEN '2014-01-01' AND '2014-12-11'
GROUP BY
DATENAME(month, Act_Supp_Negotiation_Date),
DATEPART(month, Act_Supp_Negotiation_Date) ) as res
order by
res.SortOrder
This will give a result like:
Table 1
Count Month Status SortOrder
--------------------------------------------------
167 January Analysis 1
631 January Negotiated 1
70 February Analysis 2
237 February Negotiated 2
and so on..
I want a result like this:
Table 2
AnalysisCount NegotiatedCount Month SortOrder
---------------------------------------------------------
167 631 January 1
70 237 February 2
Give it a try:
;WITH CTEResult AS
(
select
res.Count, res.Month, res.status, res.SortOrder
from
(SELECT
count(analysis_complete_date) as Count,
DATENAME(month, analysis_complete_date) AS Month,
DATEPART(month, analysis_complete_date) AS SortOrder,
'Analysis' as status
FROM
SCN_Part_Details AS parts
WHERE
analysis_complete_date BETWEEN '2014-01-01' AND '2014-12-11'
GROUP BY
DATENAME(month, analysis_complete_date),
DATEPART(month, analysis_complete_date)
union
SELECT
count(Act_Supp_Negotiation_Date) as Count,
DATENAME(month, Act_Supp_Negotiation_Date) AS Month,
DATEPART(month, Act_Supp_Negotiation_Date) AS SortOrder,
'Negotiated' as status
FROM
SCN_Part_Details AS parts
WHERE
Act_Supp_Negotiation_Date BETWEEN '2014-01-01' AND '2014-12-11'
GROUP BY
DATENAME(month, Act_Supp_Negotiation_Date),
DATEPART(month, Act_Supp_Negotiation_Date) ) as res
)
SELECT DISTINCT
(SELECT TOP 1 Count FROM CTEResult A WHERE A.Month = C.Month AND A.STATUS = 'Analysis' AND A.SortOrder = C.SortOrder) AS AnalysisCount,
(SELECT TOP 1 Count FROM CTEResult B WHERE B.Month = C.Month AND B.STATUS = 'Negotiated' AND B.SortOrder = C.SortOrder) AS
NegotiatedCount, C.Month, C.SortOrder
FROM CTEResult C
Once you got your result, you can pivot the table to get the desired result.
create table #temp
(
quantity int,
month varchar(20),
status varchar(20),
sortorder int
)
insert into #temp values
(167,'January' ,'Analysis', 1 ),
(631,'January' ,'Negotiated',1 ),
(70 ,'February','Analysis', 2 ),
(237,'February','Negotiated', 2 )
select max(analysis) as analysiscount
,max(negotiated) as negotiatedcount
,month
,max(sortorder) as sortorder
from
(
select *
from #temp
pivot
(max(quantity) for status in ([analysis],[negotiated])) as pi
) t
group by month
order by sortorder;

Multiple select against one table in one query

I'm trying to construct a select statement that will give me a percentage value for each month and user.
I have a table with rows that looks like this;
Table name: pytrans
tTransDate tArtCode tTime tSignature
20120801 DKK 1 30JK
20120801 AD 1.5 30JK
20120802 DKB 3 40AK
20120903 MI 2 45TR
20120904 DKK 2 30JK
20120904 DKB 2 30JK
The select(s) should give me the percentage of how much time spent on tArtCode DKB or DKK for each signature and month of all time spent on all tArtCode. So from the above example the select should give me 40% for signature 30JK in month 8 and 100% for signature 30JK in month 9.
I have tried different kind of sql select statements but It doesn’t seem to get 100% right.
This is what I’ve got;
select DATEPART(YY, tTransdatum) AS Year, DATEPART(mm, tTransdatum) AS Month, tSignatur,
(select SUM(tAntal) AS SumPart from pytrans where tSignatur = '30JK' AND (tArtikelkod = 'DKK' OR tArtikelkod = 'DKB'))
/(select DATEPART(YY, tTransdatum) AS Year, DATEPART(mm, tTransdatum) AS Month, SUM(tAntal) AS SumTot from pytrans where tSignatur = '30JK' GROUP BY Year, Month, SumTot) * 100
From pytrans where tSignatur = '30JK' GROUP BY DATEPART(mm, tTransdatum), DATEPART(YY, tTransdatum), tSignatur
This SQL don’t work the error is that I can’t group Year, Month, SumTot. Also i get error; Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
This next sql select give me what i want but I’m to specific what I’m asking for... so to speak. If I use this sql i then need to have a sql query for every signature and every month, and that’s not really creative.
select TOP 1 DATEPART(YY, tTransdatum) AS Year, DATEPART(mm, tTransdatum) AS Month, tSignatur,
SumProc = (select SUM(tAntal) from pytrans
where tSignatur = '30JK' AND (tArtikelkod NOT LIKE 'FL' AND tArtikelkod NOT LIKE 'SEM' AND tArtikelkod NOT LIKE 'KOMPIN') AND (tArtikelkod = 'DKK' OR tArtikelkod = 'DKB') AND tTransdatum BETWEEN '20121101' AND '20121131')
/ (select SUM(tAntal) from pytrans
where tSignatur = '30JK' AND (tArtikelkod NOT LIKE 'FL' AND tArtikelkod NOT LIKE 'SEM' AND tArtikelkod NOT LIKE 'KOMPIN') AND tTransdatum BETWEEN '20121101' AND '20121131') * 100
from pytrans
Where tSignatur = '30JK' AND tTransdatum BETWEEN '20121101' AND '20121131'
group by tTransdatum, tSignatur
I’ve also tried Union but that doesn’t seem to work for me.
I really need help with this! Thanks!
Create Table #pytrans(tTransdatum datetime, tArtCode varchar(10), tAntal float, tSignature varchar(10))
insert into #pytrans Values('20120801', 'DKK', 1 ,'30JK')
insert into #pytrans Values('20120801', 'AD', 1.5 ,'30JK')
insert into #pytrans Values('20120802', 'DKB', 3 ,'40AK')
insert into #pytrans Values('20120903', 'MI', 2 ,'45TR')
insert into #pytrans Values('20120904', 'DKK', 2 ,'30JK')
insert into #pytrans Values('20120904', 'DKB', 2 ,'30JK')
Select a.Year,a.Month,a.tSignature,a.SumPart as aAll,b.SumPart as bAll,Case when b.SumPart =0 then NULL else a.SumPart/b.SumPart * 100 end as [Percent]
from
(select DATEPART(YY, tTransdatum) AS Year, DATEPART(mm, tTransdatum) AS Month, tSignature
,SUM(tAntal) AS SumPart
from #pytrans
where tSignature = '30JK' AND tArtCode in( 'DKK' ,'DKB')
Group by DATEPART(YY, tTransdatum) , DATEPART(mm, tTransdatum) , tSignature) a
Left Join
(select DATEPART(YY, tTransdatum) AS Year, DATEPART(mm, tTransdatum) AS Month, tSignature
,SUM(tAntal) AS SumPart
from #pytrans
where tSignature = '30JK'
Group by DATEPART(YY, tTransdatum) , DATEPART(mm, tTransdatum) , tSignature) b
on a.Month=b.Month and a.Year =b.Year and a.tSignature = b.tSignature