How to select data based Group by ID,Year,Month in sqlserver? - sql

How to get the data based on the given below format:
Id name year month amount
1 A 2012 jan 100
1 A 2012 jan 900
1 A 2012 jan 300
1 A 2012 apr 100
1 A 2012 apr 500
2 B 2013 may 100
Output would be in the below mentioned form, if name, year, and month in parameter,
Id name Jan feb mar Apr may jun ...... jan .....may total
1 A 1300 0 0 600 0 0 ..... 0 ...... 0 1900
2 B 0 0 0 0 0 0.........0.......100 100

declare #t table (Id INT,name VARCHAR(10),years VARCHAR(10),months VARCHAR(10),amt INT )
insert into #t (Id,name,years,months,amt)values (1,'A','2012','jan',100)
insert into #t (Id,name,years,months,amt)values (2,'A','2012','jan',100)
insert into #t (Id,name,years,months,amt)values (3,'A','2012','apr',200)
insert into #t (Id,name,years,months,amt)values (4,'A','2012','apr',100)
insert into #t (Id,name,years,months,amt)values (5,'B','2013','may',200)
Select id,
name,
ISNULL(jan,0) As Jan,
ISNULL(feb,0) As FEb,
ISNULL(mar,0) As Mar,
ISNULL(apr,0)As Apr,ISNULL(JUn,0)As Jun,ISNULL(jul,0)As jul,ISNULL(aug,0)As aug
from
(Select distinct t.ID,t.name,t.years,t.months As Months,t.amt
from #t t)t
PIVOT (SUM(amt)FOR Months IN( [jan],
[feb],
[mar],
[apr],[JUn],[jul],[aug]))p

You need to use PIVOT to get result like you mentioned
Here is one example to use PIVOT
and your sql syntex like
SELECT * FROM (SELECT t.id,t.name,t.month,t.amount,(SELECT SUM(t2.amount) FROM dbo.test AS t2 GROUP BY t2.name HAVING t2.name= t.name ) AS total FROM dbo.test AS t) as s
PIVOT
(
SUM(Amount)
FOR [month] IN (jan, feb, mar, apr,
may, jun, jul, aug, sep, oct, nov, dec)
)AS pivots
Example

I think this might need a dynamic pivot?
CREATE TABLE #Data (
Id INT,
name VARCHAR(1),
[year] INT,
[month] VARCHAR(3),
amount INT);
INSERT INTO #Data VALUES (1, 'A', 2012, 'jan', 100);
INSERT INTO #Data VALUES (1, 'A', 2012, 'jan', 900);
INSERT INTO #Data VALUES (1, 'A', 2012, 'jan', 300);
INSERT INTO #Data VALUES (1, 'A', 2012, 'apr', 100);
INSERT INTO #Data VALUES (1, 'A', 2012, 'apr', 500);
INSERT INTO #Data VALUES (2, 'B', 2013, 'may', 100);
DECLARE #cols VARCHAR(1024);
SELECT
#Cols = STUFF((
SELECT DISTINCT
',' + QUOTENAME(CONVERT(VARCHAR(4), [year]) + '/' + [month])
FROM
#Data
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1 ,1 ,'');
DECLARE #Query VARCHAR(MAX);
SELECT #Query = '
WITH Aggregated AS (
SELECT
Id,
name,
CONVERT(VARCHAR(4), [year]) + ''/'' + [month] AS YearMonth,
SUM(amount) AS amount
FROM
#Data
GROUP BY
Id,
name,
[year],
[month])
SELECT
*
FROM
Aggregated
PIVOT (
SUM(amount)
FOR YearMonth IN (' + #cols + ')
) p;';
EXEC (#Query);
Results look like this:
Id name 2012/apr 2012/jan 2013/may
1 A 600 1300 NULL
2 B NULL NULL 100

Related

SQL Group Count

I have a table like this
Date County Location
2020-01-01 abc west
2020-01-02 abc north
2020-02-01 xzy west
2020-02-02 xzy east
2020-02-03 xyz east
Can we group and count so it can become
County jan feb
abc 2
xyz 3
Location jan feb
west 1
north 1
west 1
east 2
Thank you
Try this as the base query and then write a pivot query based on this query result as shown in the demo link.
For your reference FROM - Using PIVOT and UNPIVOT.
Select country
, FORMAT([date], 'MMMM') as Month
, count(*) as Tot
from YourTable
group by country, FORMAT([date], 'MMMM')
Pivot query needed an aggregate function. Here is the complete query.
create table YourTable
([Date] Date
, Country varchar(20)
, Location varchar(20))
insert into YourTable values
('2020-01-01', 'abc', 'west'),
('2020-01-02', 'abc', 'north'),
('2020-02-01', 'xzy', 'west'),
('2020-02-02', 'xzy', 'east'),
('2020-02-03', 'xyz', 'east')
Select * into #temp from(
Select country
, FORMAT([date], 'MMMM') as Month
, count(*) as Tot
from YourTable
group by country, FORMAT([date], 'MMMM')
)a
--Select * from #temp
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.Month)
FROM #temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT country, ' + #cols + ' from
(
select Country
, Month
, Tot
from #temp
) x
pivot
(
max(Tot)
for Month in (' + #cols + ')
) p '
execute(#query)
Live db<>fiddle demo.
Use conditional aggregation along with grouping sets:
select county, location,
sum(case when date >= '2020-01-01' and date < '2020-02-01' then 1 end) as jan,
sum(case when date >= '2020-02-01' and date < '2020-03-01' then 1 end) as feb
from t
group by grouping sets ( (country), (location) );

My Sql PIVOT Query Is Not Working As Intended

I'm using the following SQL query to return a table with 4 columns Year, Month, Quantity Sold, Stock_Code,
SELECT yr, mon, sum(Quantity) as Quantity, STOCK_CODE
FROM [All Stock Purchased]
group by yr, mon, stock_code
order by yr, mon, stock_code
This is an example of some of the data BUT I have about 3000 Stock_Codes and approx 40 x yr/mon combinations.
yr mon Quantity STOCK_CODE
2015 4 42 100105
2015 4 220 100135
2015 4 1 100237
2015 4 2 100252
2015 4 1 100277
I want to pivot this into a table which has a row for each SKU and columns for every Year/Month combination.
I have never used Pivot before so have done some research and have created a SQL query that I believe should work.
select * from
(SELECT yr,
mon, Quantity,
STOCK_CODE
FROM [All Stock Purchased]) AS BaseData
pivot (
sum(Quantity)
For Stock_Code
in ([4 2015],[5 2015] ...........
) as PivotTable
This query returns a table with Yr as col1, Mon as col2 and then 4 2015 etc as subsequent columns. Whereas I want col1 to be Stock_Code and col2 to show the quantity of that stock code sold in 4 2015.
Would really like to understand what is wrong with my code above please.
The following query using dynamic PIVOT should do what you want:
CREATE TABLE #temp (Yr INT,Mnt INT,Quantity INT, Stock_Code INT)
INSERT INTO #temp VALUES
(2015,4,42,100105),
(2015,4,100,100105),
(2015,5,220,100135),
(2015,4,1,100237),
(2015,4,2,100252),
(2015,7,1,100277)
DECLARE #pvt NVARCHAR(MAX) = '';
SET #pvt = STUFF(
(SELECT DISTINCT N', ' + QUOTENAME(CONVERT(VARCHAR(10),Mnt) +' '+ CONVERT(VARCHAR(10),Yr)) FROM #temp FOR XML PATH('')),1,2,N'');
EXEC (N'
SELECT pvt.* FROM (
SELECT Stock_Code
,CONVERT(VARCHAR(10),Mnt) +'' ''+ CONVERT(VARCHAR(10),Yr) AS [Tag]
,Quantity
FROM #temp )a
PIVOT (SUM(Quantity) FOR [Tag] IN ('+#pvt+')) pvt');
Result is as below,
Stock_Code 4 2015 5 2015 7 2015
100105 142 NULL NULL
100135 NULL 220 NULL
100237 1 NULL NULL
100252 2 NULL NULL
100277 NULL NULL 1
You can achieve this without using pivoting.
SELECT P.`STOCK_CODE`,
SUM(
CASE
WHEN P.`yr`=2015 AND P.`mon` = '1'
THEN P.`Quantity`
ELSE 0
END
) AS '1 2015',
SUM(
CASE
WHEN P.`yr`=2015 AND P.`mon` = '2'
THEN P.`Quantity`
ELSE 0
END
) AS '2 2015',
SUM(
CASE
WHEN P.`yr`=2015 AND P.`mon` = '3'
THEN P.`Quantity`
ELSE 0
END
) AS '3 2015',
FROM [All Stock Purchased] P
GROUP BY P.`STOCK_CODE`;

Adding all the amounts per month using sql server

Here is my data
date amount
2017-07-10 15.00
2017-07-10 15.00
2017-07-28 25.00
2017-08-01 100.00
2017-08-12 15.00
2017-08-29 200.00
2017-09-18 105.00
2017-09-21 200.00
2017-09-23 25.00
2017-10-12 15.00
2017-10-14 500.00
2017-11-01 200.00
2017-11-02 200.00
I want to add it by month so what we will get that in June i got a total of 55, August i will get 315, September 330, October 515, November 400 and the past dates with no amount will be 0 how will i do that?
Here is my temporary table codes:
create table #TempTable
(month varchar(50),
amount decimal(18,2))
insert into #TempTable (month)
SELECT TOP 12
DATENAME(MONTH, DATEADD(MONTH,ROW_NUMBER() OVER (ORDER BY object_id) - 1,0))
FROM sys.columns
create table #Data
(date date,
amount decimal(18,2))
insert into #Data(date,amount) values('2017-07-10',15.00)
insert into #Data(date,amount) values('2017-07-10',15.00)
insert into #Data(date,amount) values('2017-07-28',25.00)
insert into #Data(date,amount) values('2017-08-01',100.00)
insert into #Data(date,amount) values('2017-08-12',15.00)
insert into #Data(date,amount) values('2017-08-29',200.00)
insert into #Data(date,amount) values('2017-09-18',105.00)
insert into #Data(date,amount) values('2017-09-21',200.00)
insert into #Data(date,amount) values('2017-09-23',25.00)
insert into #Data(date,amount) values('2017-10-12',15.00)
insert into #Data(date,amount) values('2017-10-14',500.00)
insert into #Data(date,amount) values('2017-11-01',200.00)
insert into #Data(date,amount) values('2017-11-02',200.00)
select * from #Data
select * from #TempTable
drop table #TempTable
drop table #Data
PS. Just update the #TempTable and put the total on it thank you :)
Use the below code:
SELECT Res1.[Month]
,ISNULL(Res2.Amount,0)
FROM #TempTable Res1
LEFT JOIN
(
select DATENAME(MONTH,Res1.date) AS [Month]
,SUM(amount) AS Amount
from #Data Res1
GROUP BY DATENAME(MONTH,Res1.date)
)Res2 ON Res2.[Month] = Res1.[Month]
SELECT a.Month,SUM(ISNULL(b.Amount,0))
FROM #TempTable a
LEFT JOIN #Data b
ON a.Month = DATENAME(MONTH,date)
GROUP BY a.Month
for update
UPDATE a
SET Amount = ISNULL(GroupSuma,0)
FROM #TempTable a
LEFT JOIN
(
select DATENAME(MONTH,date) as month, SUM(b.Amount) as GroupSuma
FROM #Data b
GROUP BY DATENAME(MONTH,date)
) as c
ON a.Month = c.Month
update temptable from data table
update #TempTable
set amount = d.amount from ( select datename(month, date) date
, SUM(amount) amount from #Data
group by datename(month, date)
) d inner join #TempTable t on t.month = d.date
select * from #TempTable
One of your requirements is:
past dates with no amount will be 0
Your dataset didn't include this so I've added two additional rows in the example code below. I also added a different year to illustrate what happens with different years. I UNION ALL the values from #data with a CTE that select years, every month# of year, and 0. When SUM'ed, most of the 0 entries are eliminated, but months in the year without values in #Data remain with amount = 0. This result is subqueried to eliminate the 0 rows out of range of the min and max dates in #data.
create table #Data (date date, amount decimal(18,2))
insert into #Data(date,amount) values('2017-07-10',15.00)
insert into #Data(date,amount) values('2017-07-10',15.00)
insert into #Data(date,amount) values('2017-07-28',25.00)
insert into #Data(date,amount) values('2017-08-01',100.00)
insert into #Data(date,amount) values('2017-08-12',15.00)
insert into #Data(date,amount) values('2017-08-29',200.00)
insert into #Data(date,amount) values('2017-09-18',105.00)
insert into #Data(date,amount) values('2017-09-21',200.00)
insert into #Data(date,amount) values('2017-09-23',25.00)
insert into #Data(date,amount) values('2017-10-12',15.00)
insert into #Data(date,amount) values('2017-10-14',500.00)
insert into #Data(date,amount) values('2017-11-01',200.00)
insert into #Data(date,amount) values('2017-11-02',200.00)
--additional test values
insert into #Data(date,amount) values('2017-05-04',5.00)
insert into #Data(date,amount) values('2018-02-22',1.00)
DECLARE #minYear int = (SELECT YEAR(MIN(date)) FROM #data)
,#minMonth int = (SELECT MONTH(MIN(date)) FROM #data)
,#maxYear int = (SELECT MAX(YEAR(date)) FROM #data)
,#maxMonth int = (SELECT MONTH(MAX(date)) FROM #data);
WITH cteYear AS
(
SELECT #minYear AS num
UNION ALL
SELECT num + 1 FROM cteYear WHERE num + 1 <= #maxYear
)
SELECT dT.dateyear
,DateName( month , DateAdd( month , dT.datemonth, -1 ) ) AS [month]
,SUM(dT.amount) AS [Sum Amount]
FROM (
SELECT YEAR(date) AS [dateyear], MONTH(date) AS [datemonth], amount -- AS [SumAmount]
FROM #Data D
UNION ALL
SELECT num, monthlist.month, 0
FROM cteYear CROSS JOIN (SELECT 1 AS [month] UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
) AS monthlist
) AS dT
WHERE (#minYear <> #maxYear AND dateyear = #minYear AND datemonth >= #minMonth)
OR
(#minYear <> #maxYear AND dateyear = #maxYear AND datemonth <= #maxMonth)
OR
(#minYear <> #maxYear AND dateyear <> #minYear AND dateyear <> #maxYear)
OR
(#minYear = #maxYear AND datemonth >= #minMonth AND datemonth <= #maxMonth)
GROUP BY dateyear, datemonth
ORDER BY dateyear, datemonth
Gives output:
dateyear month Sum Amount
2017 May 5.00
2017 June 0.00
2017 July 55.00
2017 August 315.00
2017 September 330.00
2017 October 515.00
2017 November 400.00
2017 December 0.00
2018 January 0.00
2018 February 1.00

Select sum with other table in SQL

How do I select sum with other table if I have data like below:
Table Member
MemberID Name DateJoin
M0001 John 01/01/2015
M0002 Willy 03/20/2016
M0003 Teddy 02/01/2017
etc....
Table Transaction
MemberID TransDate Total
M0002 02/01/2015 100000
M0002 02/28/2015 222000
M0001 01/01/2016 150000
M0001 01/26/2017 160000
M0002 01/25/2017 160000
M0003 02/01/2017 9000
I want the result as a sum of how many times the member transaction in shop in years 2015-2017
The result I want it's:
MemberID 2015 2016 2017
M0001 0 1 1
M0002 2 0 1
M0003 0 0 1
How many members will appear in Result although don't have transaction too.
try dynamic sql .
--load in #temp table
select MemberID , datepart (yyyy ,TransDate ) as TransDate ,COUNT(*)as cnt into #temp from [Transaction]
group by MemberID , datepart (yyyy ,TransDate )
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.TransDate)
FROM #temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT MemberID, ' + #cols + ' from
(
select MemberID
, cnt
, TransDate
from #temp
) x
pivot
(
max(cnt)
for TransDate in (' + #cols + ')
) p '
execute(#query)
drop #temp -- cleanup of #temp table
CREATE TABLE #Table1
([MemberID] varchar(5), [Name] varchar(5), [DateJoin] datetime)
;
INSERT INTO #Table1
([MemberID], [Name], [DateJoin])
VALUES
('M0001', 'John', '2015-01-01 00:00:00'),
('M0002', 'Willy', '2016-03-20 00:00:00'),
('M0003', 'Teddy', '2017-02-01 00:00:00')
;
CREATE TABLE #Table2
([MemberID] varchar(5), [TransDate] datetime, [Total] int)
;
INSERT INTO #Table2
([MemberID], [TransDate], [Total])
VALUES
('M0002', '2015-02-01 00:00:00', 100000),
('M0002', '2015-02-28 00:00:00', 222000),
('M0001', '2016-01-01 00:00:00', 150000),
('M0001', '2017-01-26 00:00:00', 160000),
('M0002', '2017-01-25 00:00:00', 160000),
('M0003', '2017-02-01 00:00:00', 9000)
;
select MemberID,[2015], [2016], [2017]
from
(
select a.MemberID,a.name,a.DateJoin,year(b.TransDate)[year],b.Total from #Table1 A join
#Table2 B on a.MemberID=b.MemberID
) src
pivot
(
count(total)
for year in ([2015], [2016], [2017])
) piv;
output
MemberID 2015 2016 2017
M0001 0 1 1
M0002 2 0 1
M0003 0 0 1
IN 2000
SELECT MEMBERID, COUNT(CASE WHEN YEAR=2015 THEN YEAR END ) AS [2015],
COUNT(CASE WHEN YEAR=2016 THEN YEAR END ) AS [2016],
COUNT(CASE WHEN YEAR=2017 THEN YEAR END ) AS [2017]
FROM (
SELECT A.MEMBERID,A.NAME,A.DATEJOIN,YEAR(B.TRANSDATE)[YEAR],B.TOTAL FROM #TABLE1 A JOIN
#TABLE2 B ON A.MEMBERID=B.MEMBERID)A
GROUP BY MEMBERID
It seems there is no information you need from table member. So select from table transaction alone and count conditionally.
select
memberid,
count(case when year(transdate) = 2015 then 1 end) as [2015],
count(case when year(transdate) = 2016 then 1 end) as [2016],
count(case when year(transdate) = 2017 then 1 end) as [2017]
from transaction
group by memberid
order by memberid;
If you want to include members that don't have any transaction, then you do need a join (an outer join that is):
select
m.memberid,
count(case when year(t.transdate) = 2015 then 1 end) as [2015],
count(case when year(t.transdate) = 2016 then 1 end) as [2016],
count(case when year(t.transdate) = 2017 then 1 end) as [2017]
from member m
left join transaction t on t.memberid = m.memberid
group by m.memberid
order by m.memberid;

Three column SQL PIVOT

How do I do a sql pivot of data that looks like this, USING the SQL PIVOT command ?
id | field | value
---------------------------------------
1 | year | 2011
1 | month | August
2 | year | 2009
1 | day | 21
2 | day | 31
2 | month | July
3 | year | 2010
3 | month | January
3 | day | NULL
Into something that looks like this:
id | year | month | day
-----------------------------
1 2011 August 21
2 2010 July 31
3 2009 January NULL
Try something like this:
DECLARE #myTable AS TABLE([ID] INT, [Field] VARCHAR(20), [Value] VARCHAR(20))
INSERT INTO #myTable VALUES ('1', 'year', '2011')
INSERT INTO #myTable VALUES ('1', 'month', 'August')
INSERT INTO #myTable VALUES ('2', 'year', '2009')
INSERT INTO #myTable VALUES ('1', 'day', '21')
INSERT INTO #myTable VALUES ('2', 'day', '31')
INSERT INTO #myTable VALUES ('2', 'month', 'July')
INSERT INTO #myTable VALUES ('3', 'year', '2010')
INSERT INTO #myTable VALUES ('3', 'month', 'January')
INSERT INTO #myTable VALUES ('3', 'day', NULL)
SELECT [ID], [year], [month], [day]
FROM
(
SELECT [ID], [Field], [Value] FROM #myTable
) t
PIVOT
(
MIN([Value]) FOR [Field] IN ([year], [month], [day])
) AS pvt
ORDER BY pvt.[year] DESC
Which will yield results of:
ID year month day
1 2011 August 21
3 2010 January NULL
2 2009 July 31
;WITH DATA(id,field,value) AS
(
SELECT 1,'year','2011' UNION ALL
SELECT 1,'month','August' UNION ALL
SELECT 2,'year','2009' UNION ALL
SELECT 1,'day ','21' UNION ALL
SELECT 2,'day ','31' UNION ALL
SELECT 2,'month','July' UNION ALL
SELECT 3,'year','2010' UNION ALL
SELECT 3,'month','January' UNION ALL
SELECT 3,'day ',NULL
)
SELECT id,
year,
month,
day
FROM DATA PIVOT (MAX(value) FOR field IN ([year], [month], [day])) AS Pvt
SELECT
id,
MAX(CASE WHEN RK=3 THEN VAL ELSE '' END) AS "YEAR",
MAX(CASE WHEN RK=2 THEN VAL ELSE '' END) AS "MONTH",
MAX(CASE WHEN RK=1 THEN VAL ELSE '' END) AS "DAY"
FROM
(
SELect
ID,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY YEAR1 ASC) RK,
VAL
FROM TEST3)A
GROUP BY 1
ORDER BY 1;