SQL Server group pivot table according to id - sql

I have a table called 'info':
|InfoId | OtherId | Year | InfoNo |
-------------------------------------
|1 | 1 | 2012 | abc |
|2 | 1 | 2013 | def |
|3 | 1 | 2014 | ghi |
I want to get this result:
| OtherId | 2012 | 2013 | 2014 |
---------------------------------
| 1 | abc | def | ghi |
i tried using:
SELECT *
FROM info
PIVOT (MAX(InfoNo)
FOR Year in ([2012],[2013],[2014])) AS pvt
where OtherId= '1'
But instead, I get this result:
| OtherId | 2012 | 2013 | 2014 |
---------------------------------
| 1 | abc | | |
| 1 | | def | |
| 1 | | | ghi |
How do I make the three rows group as one row according to 'OtherId'?
EDIT
I updated my SQL to the following and manage to get the result I wanted as well:
SELECT
OtherId,
MAX(case WHEN Year = '2012' THEN InvoiceNo ELSE NULL end) AS [2012],
MAX(case WHEN Year = '2013' THEN InvoiceNo ELSE NULL end) AS [2013],
MAX(case WHEN Year = '2014' THEN InvoiceNo ELSE NULL end) AS [2014]
FROM info
Thanks all for helping me.

You need to group your result by OtherId, I did a quick test and here's the result:
Select * FROM info
InfoId OtherId Year InfoNo
----------- ----------- ----------- ----------
1 1 2012 abc
2 1 2013 edf
3 1 2014 ghk
SELECT
pvt.OtherId,
MAX([2012]) AS '2012',
MAX([2013]) AS '2013',
MAX([2014]) AS '2014'
FROM info AS src
PIVOT (
MAX(InfoNo)
FOR [Year] IN ([2012],[2013],[2014]))
AS pvt
GROUP BY pvt.OtherId
Result:
OtherId 2012 2013 2014
----------- ---------- ---------- ----------
1 abc edf ghk
Hope that helps your cause.

IF OBJECT_ID('Tempdb..#Temp') IS NOt NUll
Drop Table #Temp
;With cte(InfoId ,OtherId ,[Year],InfoNo)
AS
(
SELECT 1,1,'2012' , 'abc' Union all
SELECT 2,1,'2013' , 'def' Union all
SELECT 3,1,'2014' , 'ghi'
)
SELECT * INTO #Temp FROM cte
DECLARE #dynamicCol nvarchar(max),#dynamicCol2 nvarchar(max),
#Sql nvarchar(max)
SELECT #dynamicCol=STUFF((SELECT DISTINCT ', ' + QUOTENAME(Year) FROM #Temp
FOR XML PATH('')),1,1,'')
SELECT #dynamicCol2=STUFF((SELECT DISTINCT ', ' + 'MAX('+ QUOTENAME(Year) +' )' +' AS '+ QUOTENAME(Year) FROM #Temp
FOR XML PATH('')),1,1,'')
SET #Sql= N' SELECT [OtherId] , '+ #dynamicCol2 +' From
(
SELECT InfoId ,OtherId ,[Year],InfoNo From
#temp
)AS Src
PIVOT
(
MAX([InfoNo]) For [Year] IN ('+#dynamicCol+')
)
AS Pvt
GROUP BY Pvt.OtherId
'
PRINT #Sql
EXEC(#Sql)
OutPut
| OtherId | 2012 | 2013 | 2014 |
---------------------------------
| 1 | abc | def | ghi |

Related

How to convert unknown values in column to row in SQL Server [duplicate]

This question already has answers here:
SQL Server dynamic PIVOT query?
(9 answers)
Closed 3 years ago.
How to convert unknown values in column to row with fixed column and sum value in another column in SQL Server?
This example
| Id | Date | Amount1 | Amount2
+----+------+---------+--------
| 1 | 2018 | 1000 | 100
| 2 | 2018 | 2000 | 200
| 2 | 2018 | 3000 | 300
| 1 | 2019 | 4000 | 400
| 1 | 2019 | 5000 | 500
| .. | .... | .... | ...
I want this
| Id | 2018Amount1 | 2018Amount2 | 2019Amount1 | 2019Amount2 | ...
+----+-------------+-------------+-------------+-------------+-------
| 1 | 1000 | 100 | 9000 | 900 | ...
| 2 | 5000 | 500 | 0 | 0 | ...
You can use dynamic pivot
DECLARE #ColName NVARCHAR(MAX) =''
SELECT #ColName = #ColName + ', '+ ColName
FROM ( SELECT DISTINCT QUOTENAME( CAST([Date] AS VARCHAR(4)) + 'Amount1')
+ ', ' + QUOTENAME(CAST([Date] AS VARCHAR(4)) + 'Amount2') ColName FROM TestTable )T
SET #ColName = STUFF (#ColName,1,1,'')
DECLARE #SqlText NVARCHAR(MAX) =
'SELECT * FROM (
SELECT Id, CAST([Date] AS VARCHAR(4)) + ''Amount1'' AS [Date], Amount1 AS Amount FROM TestTable
UNION
SELECT Id, CAST([Date] AS VARCHAR(4)) + ''Amount2'' [Date], Amount2 AS Amount FROM TestTable
) SRC
PIVOT(SUM(Amount) FOR Date IN (' + #ColName+ ') ) AS PVT'
EXECUTE sp_executesql #SqlText
Use conditional aggregation :
select Id,
sum( case when Date = 2018 then Amount1 end ) as "2018Amount1",
sum( case when Date = 2018 then Amount2 end ) as "2018Amount2",
sum( case when Date = 2019 then Amount1 end ) as "2019Amount1",
sum( case when Date = 2019 then Amount2 end ) as "2019Amount2"
from tab
group by Id

How to convert Rows into Columns based on value

I have following data in a table, in table each group contain two values for ON/OFF in two rows. I want to convert rows into new columns "Col1=>Col1_Status_ON/OFF" new name based on status
here is the detail:
====================================================
| Group | DateTime | Status | Col1 | Col2 |
====================================================
| Group1 | 01-Jan-2019 | ON | 101 | 102 |
| Group1 | 01-Jan-2019 | OFF | 201 | 202 |
| Group2 | 01-Jan-2019 | ON | 301 | 302 |
| Group2 | 01-Jan-2019 | OFF | 401 | 402 |
| Group3 | 01-Jan-2019 | ON | 501 | 502 |
| Group4 | 01-Jan-2019 | OFF | 601 | 602 |
====================================================
I want query that return as follows
=======================================================================================
| Group | DateTime |Col1_Satus_ON|Col1_Satus_OFF|Col2_Status_ON|Col2_Status_OFF|
=======================================================================================
| Group1 | 01-Jan-2019| 101 | 201 | 102 | 202 |
| Group2 | 01-Jan-2019| 301 | 401 | 302 | 402 |
| Group3 | 01-Jan-2019| 501 | 601 | 502 | 602 |
=======================================================================================
below are the SQL to generate table data.
DROP TABLE IF EXISTS dbo.#MyTable;
SELECT CONVERT(VARCHAR(100),'')[Group], GETDATE()[DateTime],
CONVERT(VARCHAR(100),'')[Status],(0)[Col1],(0)[Col2]
INTO #MyTable WHERE 1=2;
INSERT INTO #MyTable ([Group],[Datetime],[Status],[Col1],[Col2])
SELECT 'Group1','01-Jan-2019 01:02:03','ON' ,101,102 UNION
SELECT 'Group1','01-Jan-2019 01:02:03','OFF',201,202 UNION
SELECT 'Group2','01-Jan-2019 01:02:03','ON' ,301,302 UNION
SELECT 'Group2','01-Jan-2019 01:02:03','OFF',401,402 UNION
SELECT 'Group3','01-Jan-2019 01:02:03','ON' ,501,502 UNION
SELECT 'Group3','01-Jan-2019 01:02:03','OFF',601,602;
SELECT * FROM #MyTable;
please suggest the query,
Here is a working dynamic pivot as folks suggested
Example
Declare #UnPiv varchar(max),#SQL varchar(max)
Set #UnPiv = Stuff(( Select ','+quotename(name)
From sys.dm_exec_describe_first_result_set(N'Select top 1 * from #MyTable',null,null ) A
Where Name not in ('Group','DateTime','Status')
For XML Path('')),1,1,'')
Set #SQL = Stuff(( Select ','+quotename(name+Suffix)
From sys.dm_exec_describe_first_result_set(N'Select top 1 * from #MyTable',null,null ) A
Cross Join ( values ('_Status_ON')
,('_Status_OFF')
) B(Suffix)
Where Name not in ('Group','DateTime','Status')
For XML Path('')),1,1,'')
Select #SQL = '
Select *
From (
Select [Group]
,[DateTime]
,Item = concat(Item,''_Status_'',Status)
,Value
From (
Select * From #MyTable Unpivot (Value for Item in ('+#UnPiv+')) UnPiv
) A
) src
Pivot (max(Value) for Item in ('+#SQL+') ) pvt
'
--Print #SQL
Exec(#SQL)
Returns
You could use conditional aggregation:
SELECT [Group], [Datetime],
Col1_Status_ON = MIN(IIF(Status='ON', Col1, NULL)),
Col1_Status_OFF = MIN(IIF(Status='OFF', Col1, NULL)),
Col2_Status_ON = MIN(IIF(Status='ON', Col2, NULL)),
Col2_Status_OFF = MIN(IIF(Status='OFF', Col2, NULL))
FROM #Mytable
GROUP BY [Group], [Datetime];
db<>fiddle demo

Pivot Result Creation from SQL query using two tables and join

I have my first table like this, it contains platform and their platform code
+-----------+------+
| platforms | code |
+-----------+------+
| java | 1 |
| .net | 2 |
| perl | 3 |
+-----------+------+
My second table contains columns as shown below.
+-------+------+------+------+
| pname | code | year | deve |
+-------+------+------+------+
| a | 1 | 2018 | abia |
| b | 1 | 2017 | arun |
| c | 2 | 2018 | abia |
| d | 3 | 2017 | arun |
| e | 2 | 2017 | arun |
| f | 3 | 2018 | abia |
+-------+------+------+------+
Result expected in Pivot Format like this:
+-----+-------+------+------+------+
| year| deve | .net | java | perl |
+-----+-------+------+------+------+
| 2018| abia | 1 | 1 | 1 |
| 2017| arun | 1 | 1 | 1 |
+-----+-------+------+------+------+
Try this Pivot Script which meets your expectation
DECLARE #Table AS TABLE
(platforms VARCHAR(20), code INT)
INSERT INTO #Table
SELECT 'java', 1 UNION ALL
SELECT '.net', 2 UNION ALL
SELECT 'perl', 3
DECLARE #Table2 AS TABLE
(pname VARCHAR(20), code INT,[year] INT, deve VARCHAR(20))
INSERT INTO #Table2
SELECT 'a',1,2018,'abia' UNION ALL
SELECT 'b',1,2017,'arun' UNION ALL
SELECT 'c',2,2018,'abia' UNION ALL
SELECT 'd',3,2017,'arun' UNION ALL
SELECT 'e',2,2017,'arun' UNION ALL
SELECT 'f',3,2018,'abia'
SELECT [year],deve,MAX([java]) AS [java],MAX([.net]) AS [.net],MAX([perl] ) AS [perl]
FROM
(
SELECT platforms,CASE WHEN pname IS NOT NULL THEN 1 ELSE NUll END AS pname ,A.code ,deve,[year] FROM #Table2 A
INNER JOIN #Table B
ON A.code=b.code
)
AS SRC
PIVOT
(
MAX(pname) FOR platforms IN( [java],[.net],[perl] )
) AS PVT
GROUP BY [year],deve
Result
year deve java .net perl
------------------------------------
2018 abia 1 1 1
2017 arun 1 1 1
Pivot using dynamic sql approach as it fits when the columns to be added dynamically to get the specific result
CREATE TABLE #Table
(platforms VARCHAR(20), code INT)
INSERT INTO #Table
SELECT 'java', 1 UNION ALL
SELECT '.net', 2 UNION ALL
SELECT 'perl', 3
CREATE TABLE #Table2
(pname VARCHAR(20), code INT,[year] INT, deve VARCHAR(20))
INSERT INTO #Table2
SELECT 'a',1,2018,'abia' UNION ALL
SELECT 'b',1,2017,'arun' UNION ALL
SELECT 'c',2,2018,'abia' UNION ALL
SELECT 'd',3,2017,'arun' UNION ALL
SELECT 'e',2,2017,'arun' UNION ALL
SELECT 'f',3,2018,'abia'
DECLARE #Columns nvarchar(max),
#IsnullColumns nvarchar(max),
#Sql nvarchar(max)
SELECT #Columns= STUFF((SELECT ', '+QUOTENAME(platforms) FROM #Table FOR XML PATH ('')),1,1,'')
SELECT #IsnullColumns=STUFF((SELECT ', '+'MAX('+QUOTENAME(platforms)+') AS ' +QUOTENAME(platforms) FROM #Table FOR XML PATH ('')),1,1,'')
SET #Sql='
SELECT[year],deve, '+#IsnullColumns+'
FROM
( SELECT platforms,
CASE WHEN pname IS NOT NULL THEN 1 ELSE NUll END AS pname ,A.code ,deve,[year]
FROM #Table2 A
INNER JOIN #Table B
ON A.code=b.code
) AS SRC
PIVOT
(MAX(pname) FOR platforms IN('+#Columns+')
) AS PVT
GROUP BY [year],deve'
PRINT #Sql
EXEC (#Sql)
Result
year deve java .net perl
------------------------------------
2018 abia 1 1 1
2017 arun 1 1 1

Dynamic field content as Row Sql

I have the following dataset on a sql database
----------------------------------
| ID | NAME | AGE | STATUS |
-----------------------------------
| 1ASDF | Brenda | 21 | Single |
-----------------------------------
| 2FDSH | Ging | 24 | Married|
-----------------------------------
| 3SDFD | Judie | 18 | Widow |
-----------------------------------
| 4GWWX | Sophie | 21 | Married|
-----------------------------------
| 5JDSI | Mylene | 24 | Singe |
-----------------------------------
I want to query that dataset so that i can have this structure in my result
--------------------------------------
| AGE | SINGLE | MARRIED | WIDOW |
--------------------------------------
| 21 | 1 | 1 | 0 |
--------------------------------------
| 24 | 1 | 1 | 0 |
--------------------------------------
| 18 | 0 | 0 | 1 |
--------------------------------------
And the status column can be dynamic so there will be more columns to come.
Is this possible?
Since you are using SQL Server, you can use the PIVOT table operator like this:
SELECT *
FROM
(
SELECT Age, Name, Status FROM tablename
) AS t
PIVOT
(
COUNT(Name)
FOR Status IN(Single, Married, Widow)
) AS p;
SQL Fiddle Demo
To do it dynamically you have to use dynamic sql like this:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(status)
FROM tablename
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query = '
SELECT *
FROM
(
SELECT Age, Name, Status FROM tablename
) AS t
PIVOT
(
COUNT(Name)
FOR Status IN( ' +#cols + ')
) AS p;';
execute(#query);
Updated SQL Fiddle Demo

SQL separate columns by rows value (pivot)

Table1
| MODULE | COUNT | YEAR |
-------------------------
| M1 | 12 | 2011 |
| M1 | 43 | 2012 |
| M2 | 5 | 2011 |
| M3 | 24 | 2011 |
| M4 | 22 | 2011 |
| M4 | 11 | 2012 |
| M5 | 10 | 2012 |
I want to display like this
| MODULE | 2011 | 2012 |
----------------------------
| M1 | 12 | 43 |
| M2 | 5 | - |
| M3 | 24 | - |
| M4 | 22 | 11 |
| M5 | - | 10 |
This can be done using PIVOT query. Or the following:
select Module,
SUM(CASE WHEN Year='2011' then Count ELSE 0 END) as [2011],
SUM(CASE WHEN Year='2012' then Count ELSE 0 END) as [2012]
FROM T
GROUP BY Module
SQL Fiddle demo
You can use PIVOT for that:
SELECT
Module,
[2011], [2012]
FROM
(
SELECT
*
FROM Table1
) AS SourceTable
PIVOT
(
SUM([Count])
FOR [Year] IN ([2011], [2012])
) AS PivotTable;
You can also use this dynamic query if you don't have limited Year
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT distinct ',' + QUOTENAME([Year])
from Table1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = 'SELECT Module,' + #cols + '
FROM
(
Select *
FROM Table1
) dta
PIVOT
(
SUM([Count])
FOR [Year] IN (' + #cols + ')
) pvt '
EXECUTE(#query);
Result:
| MODULE | 2011 | 2012 |
----------------------------
| M1 | 12 | 43 |
| M2 | 5 | (null) |
| M3 | 24 | (null) |
| M4 | 22 | 11 |
| M5 | (null) | 10 |
See this SQLFiddle
Update
You can also use this alternative dynamic method: (Dynamic of the query given by #valex)
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT distinct ','
+ ' SUM(CASE WHEN YEAR= ''' + CAST(Year AS varchar(50))
+ ''' THEN [COUNT] ELSE ''-'' END) AS ' + QUOTENAME([Year])
from Table1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = 'SELECT Module, ' + #cols + '
FROM Table1 GROUP BY Module'
EXECUTE(#query);
See this SQLFiddle
SELECT *
FROM Tablename
PIVOT (
AVG([Count] FOR [Year] IN (2011, 2012, 2013)) AS AvgCount
)
I think you need to look into the relational operator PIVOT.
Using PIVOT and UNPIVOT
SELECT Module,
[2011], [2012]
FROM T
PIVOT (SUM(Count) FOR Year IN ([2011], [2012])) AS PivotTable;