How to create a SQL Server Pivot query? - sql

I want to create sql query result. I want to dynamically create because of inventory locations are one or more. (Example.. CTE)
Item_id Location Qty
--------------------------
1 a 1
2 b 2
3 c 3
3 a 1
2 c 2
1 b 3
Result is....
Item_id a_Location_Qty b_Location_Qty c_Location_Qty
-------------------------------------------------------
1 1 3 0
2 0 2 2
3 1 0 3

Please try below code
Create Table #Stack10072017040904(Item_id varchar(100),Location varchar(100),Qty int)
insert into #Stack10072017040904 select '1','a','1'
insert into #Stack10072017040904 select '2','b','2'
insert into #Stack10072017040904 select '3','c','3'
insert into #Stack10072017040904 select '3','a','1'
insert into #Stack10072017040904 select '2','c','2'
insert into #Stack10072017040904 select '1','b','3'
select Item_id,Isnull(a,0) a_Location_Qty
,isnull(b,0)b_Location_Qty
,isnull(c,0)c_Location_Qty
from #Stack10072017040904
pivot
(Sum(Qty) for Location in ([a],[b],c) )pvt
drop table #Stack10072017040904

Try this Dynamic Sql
Declare
#Sql nvarchar(max),
#dynamicCol nvarchar(max),
#dynamicCol2 nvarchar(max)
--Create columns Dynamically
SELECT #dynamicCol=STUFF((SELECT DISTINCT ', '+ QUOTENAME(Location )
From #Stack10072017040904 For XML PATH ('')),1,1,'')
SELECT #dynamicCol2=STUFF((SELECT DISTINCT ', '+ 'ISNULL ('+ QUOTENAME(Location )+ ','+'''0'''+')' +' AS '+Location+'_Location_Qty'
From #Stack10072017040904 For XML PATH ('')),1,1,'')
SET #Sql='
SELECT [Item_id] ,'+ #dynamicCol2 +' From
(
SELECT * From
#Stack10072017040904
)AS Src
PIVOT
(
MAX([Qty]) For [Location] IN ('+#dynamicCol+')
)
AS Pvt'
PRINT #Sql
EXEC(#Sql)
Result
Item_id a_Location_Qty b_Location_Qty c_Location_Qty
-------------------------------------------------------
1 1 3 0
2 0 2 2
3 1 0 3

Build columns dynamically and use a dynamic PIVOT:
Create Table #Test(Item_id varchar(100),Location varchar(100),Qty int)
insert into #Test values( '1','a','1')
insert into #Test values( '2','b','2')
insert into #Test values( '3','c','3')
insert into #Test values( '3','a','1')
insert into #Test values( '2','c','2')
insert into #Test values( '1','b','3')
DECLARE #cols1 AS NVARCHAR(MAX), #cols2 AS NVARCHAR(MAX), #query AS NVARCHAR(MAX);
SET #cols1 = STUFF((SELECT distinct ', isnull(' + quotename(s.Location) + ', 0) as ' + quotename(s.Location)
FROM #Test s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #cols2 = STUFF((SELECT distinct ',' + quotename(s.Location)
FROM #Test s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Item_id, ' + #cols1 + ' from
(
select Item_id
, Location
, Qty
from #Test
) x
pivot
(
max(qty)
for Location in (' + #cols2 + ')
) p '
execute(#query)
drop table #Test

Related

Required pivot for below data structured

i have data in below format.
ID question answer
1 who A
1 where B
1 when C
1 how D
i required output as below
id who where when how
1 A B C D
You can try this using dynamic pivot query.
create table #temp (ID int, question varchar(20), answer char(1))
insert into #temp values
(1, 'who', 'A'),
(1, 'where', 'B'),
(1, 'when', 'C'),
(1, 'how', 'D')
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.question)
FROM #temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Id, ' + #cols + ' from
(
select Id
,question
, answer
from #temp
) x
pivot
(
max(answer)
for question in (' + #cols + ')
) p '
execute(#query)
Live Demo
use conditional aggregation
select id,
max(case when question='who' then answer end) as "who",
max(case when question='where' then answer end) as "where",
max(case when question='when' then answer end) as "when",
max(case when question='how' then answer end) as "how"
from table_name
group by id
You may try this.
DECLARE #column AS VARCHAR(MAX), #query AS VARCHAR(MAX);
SET #column = STUFF((SELECT distinct ',' + QUOTENAME(t.question) FROM table t FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
set #query = 'SELECT Id, ' + #column + ' from
(
select Id, question, answer from table
) x
pivot
( max(answer) for question in (' + #column + ')
) p '
exec (#query)

SQL Server Dynamic pivot for an unknow number of columns

The question has been asked before, but in a slightly different scenario (one that doesn't seem to fit to my question) so..
I have data that looks like this
Name |Item |Note
George|Paperclip |Two boxes
George|Stapler |blue one
George|Stapler |red one
George|Desk lamp |No light bulb
Mark |Paperclip |One box 2"
Mark |Paperclip |One box 4"
Mark |Block Notes|a blue one
..? |..? |..?
And I would want to pivot by name, to obtain
Name |Paperclip|Stapler|Desk Lamp|Block Notes
George| 1| 2| 1| NULL
Mark | 2| NULL | NULL | 1
I've follower the examples like
Convert Rows to columns using 'Pivot' in SQL Server
but I'm far from a solution.. can someone please give me an hand?
Thanks!
edit: the actual code
drop table #temp2
SELECT DISTINCT *,
CASE WHEN Item IS NULL THEN NULL ELSE COUNT(Item) OVER(PARTITION BY Name) END CNT
INTO #TEMP2
FROM [ISPBIGFIX].[dbo].[C_INV_ErroriTavolette_v11]
DECLARE #cols NVARCHAR (MAX)
DECLARE #Columns2 NVARCHAR (MAX)
SET #cols = SUBSTRING((SELECT DISTINCT ',['+Item+']' FROM #TEMP2 GROUP BY Item FOR XML PATH('')),2,8000)
SET #Columns2 = SUBSTRING((SELECT DISTINCT ',ISNULL(['+Item+'],0) AS ['+Item+']' FROM #TEMP2 GROUP BY Item FOR XML PATH('')),2,8000)
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT Name,' + #Columns2 + ' FROM
(
SELECT Name,ErrorType,CNT FROM #TEMP2
) x
PIVOT
(
SUM(CNT)
FOR [Item] IN (' + #cols + ')
) p
WHERE Name IS NOT NULL;'
EXEC SP_EXECUTESQL #query
Try this, It follows the same example mentioned here:Convert Rows to columns using 'Pivot' in SQL Server
--Drop Sample temp Table
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
BEGIN
DROP TABLE #temp2
END
--create Sample temp Table
create Table #temp2
(
[name] varchar(255),
Item varchar(255),
note varchar(255)
)
--Insert Sample Data
insert into #temp2
values( 'George','Paperclip','Two boxes'),
('George','Stapler','blue one'),
('George','Stapler','red one'),
('George','Desk lamp','No light bulb'),
('Mark','Paperclip','One box 2'),
('Mark','Paperclip','One box 4'),
('Mark','Block Notes','a blue one')
DECLARE #cols AS NVARCHAR(MAX), #cols2 AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
--Generate Columns from Data
--Generate Columns from Data
select #cols = STUFF((SELECT ', isnull(' + QUOTENAME(Item) + ',0) as' + QUOTENAME(Item)
from #temp2
group by Item
order by Item
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #cols2 = STUFF((SELECT ', ' + QUOTENAME(Item)
from #temp2
group by Item
order by Item
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
--Pivot Query
set #query = 'SELECT [name],' + #cols + ' from
(
select [Name], Item, count(*) as xcount
from #temp2
group by Name, Item
) x
pivot
(
sum(xCount)
for Item in (' + #cols2+ ')
) p '
execute(#query);
--Drop Sample Temp Table
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
BEGIN
DROP TABLE #temp2
END
Try This Dynamic Sql
IF OBJECT_ID('dbo.TT')IS NOT NULL
DROP TABLE TT
;WITH CTE(Name ,Item ,Note)
AS
(
SELECT 'George','Paperclip' ,'Two boxes' UNION ALL
SELECT 'George','Stapler' ,'blue one' UNION ALL
SELECT 'George','Stapler' ,'red one' UNION ALL
SELECT 'George','Desk lamp' ,'No light bulb' UNION ALL
SELECT 'Mark' ,'Paperclip' ,'One box 2' UNION ALL
SELECT 'Mark' ,'Paperclip' ,'One box 4' UNION ALL
SELECT 'Mark' ,'Block Notes','a blue one'
)
SELECT *,CASE WHEN Item IS NOT NULL THEN 1 ELSE 0 END AS Item2 INTO TT FROM CTE
SELECT * FROM TT
DECLARE #Sql nvarchar(max),
#Sqlcol nvarchar(max),
#ISNULLSqlcol nvarchar(max)
SELECT #Sqlcol=STUFF((SELECT DISTINCT ', '+QUOTENAME(Item)
FROM TT FOR XML PATH ('')),1,1,'')
SELECT #ISNULLSqlcol=STUFF((SELECT DISTINCT ', '+'ISNULL(SUM('+QUOTENAME(Item) +'),''0'') AS '+QUOTENAME(Item)
FROM TT FOR XML PATH ('')),1,1,'')
SET #Sql='SELECT Name,'+#ISNULLSqlcol+'FROM
(
SELECT * FROM TT
) AS SRc
PIVOT
(
SUM(Item2) FOR Item IN('+#Sqlcol+')
) AS Pvt GROUP BY Name'
Print #Sql
EXEC (#Sql)
Try this query (I think its much more clearly). I use the code of Kashif Qureshi to create a temporary table, but my code is different in PIVOT part
--Drop Sample temp Table
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
BEGIN
DROP TABLE #temp2
END
--create Sample temp Table
create Table #temp2
(
[name] varchar(255),
Item varchar(255),
note varchar(255)
)
--Insert Sample Data
insert into #temp2
values( 'George','Paperclip','Two boxes'),
('George','Stapler','blue one'),
('George','Stapler','red one'),
('George','Desk lamp','No light bulb'),
('Mark','Paperclip','One box 2'),
('Mark','Paperclip','One box 4'),
('Mark','Block Notes','a blue one')
--- PIVOT
DECLARE #v_query VARCHAR(8000) -- main query
DECLARE #v_columns VARCHAR(8000) -- columns
SET #v_columns =''
-- Get string columns
SELECT #v_columns += '[' + CONVERT(VARCHAR, Item) +'],' FROM (SELECT DISTINCT Item FROM #temp2) AS temp
-- Delete the last comma
SET #v_columns = LEFT(#v_columns,LEN(#v_columns)-1)
-- Main query
SET #v_query = 'SELECT Name, ' + #v_columns +' FROM
(
SELECT Name, Item FROM #temp2
) T
PIVOT
(
Count(Item)
FOR Item IN ('+ #v_columns +')
) PVT'
EXEC (#v_query)
-- DROP
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL
BEGIN
DROP TABLE #temp2
END
The answer by Kashif works. Here is a version that leverages STRING_AGG
--Drop Sample temp Table
DROP TABLE IF EXISTS #temp2
--Create Sample temp Table
CREATE Table #temp2 (
[name] varchar(255),
Item varchar(255),
note varchar(255)
)
--Insert Sample Data
INSERT INTO #temp2
VALUES ( 'George','Paperclip','Two boxes'),
('George','Stapler','blue one'),
('George','Stapler','red one'),
('George','Desk lamp','No light bulb'),
('Mark','Paperclip','One box 2'),
('Mark','Paperclip','One box 4'),
('Mark','Block Notes','a blue one')
DECLARE #cols AS NVARCHAR(MAX), #cols2 AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
--Generate Columns from Data
SET #cols = (SELECT STRING_AGG (' isnull(' + QUOTENAME(Item) + ',0) as' + QUOTENAME(Item), ',') as colR
FROM (SELECT ITEM FROM (SELECT ITEM FROM #temp2 GROUP BY ITEM) x GROUP BY ITEM) Y )
SET #cols2 = (SELECT STRING_AGG (QUOTENAME(Item), ',') as colR
FROM (SELECT ITEM FROM (SELECT ITEM FROM #temp2 GROUP BY ITEM) x GROUP BY ITEM) Y )
SET #query = 'SELECT [name],' + #cols + '
FROM (
SELECT [Name], Item, COUNT(*) as xcount
FROM #temp2
GROUP BY Name, Item
) x
PIVOT (
SUM(xCount)
FOR Item IN (' + #cols2+ ')
) p '
EXECUTE (#query);
--Drop Sample Temp Table
DROP TABLE IF EXISTS #temp2

How to pivot rows into colums dynamically SQL Server

I have a request which returns something like this:
--------------------------
Tool | Week | Value
--------------------------
Test | 20 | 3
Sense | 20 | 2
Test | 19 | 2
And I want my input to look like this:
-------------------------
Tool | W20 | W19
-------------------------
Test | 3 | 2
Sense | 2 | null
Basically, for every week I need to have a new column. The number of week and of tools is dynamic.
I have tried many things but nothing worked. Anybody have a solution ?
Try this
CREATE table #tst (
Tool varchar(50), [Week] int, Value int
)
insert #tst
values
('Test', 20, 3),
('Sense', 20,2),
('Test', 19, 2)
Here is the Dynamic Query:
DECLARE #col nvarchar(max), #query NVARCHAR(MAX)
SELECT #col = STUFF((SELECT DISTINCT ',' + QUOTENAME('W' + CAST([Week] as VARCHAR))
from #tst
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = '
SELECT *
FROM (
SELECT Tool,
Value,
''W'' + CAST([Week] as VARCHAR) AS WeekNo
FROM #tst
) t
PIVOT
(
MAX(t.Value)
FOR WeekNo IN (' + #col + ')
) pv
ORDER by Tool'
EXEC (#query)
Result
Tool W20 W19
=================
Sense 2 NULL
Test 3 2
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
( Tool varchar(5), Week int, Value int)
;
INSERT INTO #temp
( Tool , Week , Value )
VALUES
('Test', 20, 3),
('Sense', 20, 2),
('Test', 19, 2)
;
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max),
#col NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ', ', '') + N'[' +'w'+ tbl.[Week] + ']'
FROM (
SELECT DISTINCT CAST([Week] AS VARCHAR)[Week]
FROM #temp
) AS tbl
SELECT #statement = 'SELECT *
FROM
(
SELECT
Tool , ''w''+ CAST(Week AS VARCHAR) week , Value
FROM
#Temp
) src
PIVOT(MAX(Value)for Week in (' + #columns + ')) as pvt
'
EXEC sp_executesql #statement = #statement
This is how I would do it ... If I understood your question correctly
if object_id('tempdb..#InputTool') is not null drop table #InputTool
create table #InputTool (Tool nvarchar(10), [20] int, [19] int)
insert into #InputTool (Tool, [20], [19])
values
('Test', 3, 2),
('Sense', 2, null)
declare #cols nvarchar(max)
select #cols = STUFF((SELECT ',' + QUOTENAME(name)
from tempdb.sys.columns
where object_id = object_id('tempdb..#InputTool')
and Column_id > 1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
declare #sqlquery nvarchar(max) =
'select Tool, Weeks, Value from (
select * from #InputTool
) as it
UNPIVOT
(
Value FOR Weeks IN (' + #cols + ')
) AS Weeks
order by Weeks desc'
execute (#sqlquery);
Give it a shot and let me know if it worked

How to provide custom name to column in pivoting

I have a table like this:
id unit
1 mm
2 cm
3 kg
When I perform pivot operation on this, I am getting result as follows:
1 2 3
mm cm kg
Is it possible to get custom column names here, something like this:
d1 d2 d3
mm cm kg
I am using Pivot for this as:
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE table #t
(id varchar(max),unit varchar(max))
insert into #t (id,unit)values
(1,'kg'),
(2,'cm'),
(3,'mm'),
(4,'m')
DECLARE #statement NVARCHAR(max)
,#columns NVARCHAR(max)
SELECT #columns = ISNULL(#columns + ',', '') + N'[' + cast(tbl.id as varchar(max)) + ']'
FROM (
SELECT DISTINCT id
FROM #t
) AS tbl
SELECT #statement = 'select *
INTO ##temp
from (
SELECT id,[unit]
FROM #t
) as s
PIVOT
(max(unit) FOR id in(' + #columns + ')) as pvt
'
EXEC sp_executesql #statement = #statement
SELECT * FROM ##temp
DROP TABLE #t
DROP TABLE ##temp
Is it possible?
Thanks
IF OBJECT_ID('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE TABLE #t (
id VARCHAR(10),
unit VARCHAR(100)
)
INSERT INTO #t (id, unit)
VALUES
('1', 'kg'),
('2', 'cm'),
('3', 'mm'),
('4', 'mm')
DECLARE #SQL NVARCHAR(MAX), #columns NVARCHAR(MAX)
SELECT #columns = STUFF((
SELECT ',[D' + id + ']'
FROM #t
FOR XML PATH('')), 1, 1, '')
SELECT #SQL = '
SELECT *
FROM (
SELECT [unit], col = N''D'' + id
FROM #t
) s
PIVOT (MAX(unit) FOR col IN (' + #columns + ')) p'
EXEC sys.sp_executesql #SQL
Just add a prefix to your ID. Example
SELECT #statement = 'select * INTO ##temp from
( SELECT [id] = ''d''+id,[unit] FROM #t ) as s
PIVOT
(max(unit) FOR id in(' + #columns + ')) as pvt '
Also it's terrible practice to use global temp tables! Especially one named ##temp
You can use a CASE expression with a dynamic sql query.
CREATE TABLE #t
(
id INT,
unit VARCHAR(2)
);
INSERT INTO #t VALUES
(1,'mm'),
(2,'cm'),
(3,'kg');
DECLARE #query AS VARCHAR(MAX);
SELECT #query = 'SELECT ' +
STUFF
(
(
SELECT DISTINCT ',MAX(CASE WHEN id = '+ CAST(id AS VARCHAR(10))
+ ' THEN unit END) AS d' + CAST(id AS VARCHAR(10))
FROM #t
FOR XML PATH('')
),
1,1,'');
SELECT #query += ' FROM #t;';
EXECUTE(#query);
Result
+----+----+----+
| d1 | d2 | d3 |
+----+----+----+
| mm | cm | kg |
+----+----+----+
SELECT #statement = 'select * INTO ##temp from ( SELECT ''d''+id AS [id],[unit] FROM #t ) as s PIVOT (max(unit) FOR id in(' + #columns + ')) as pvt '

SQL query Joining table itself

I have a following table:
TICKER DATE SHAREPRICE
--------------------------------
ABC 1.1.2015 50
XYZ 1.1.2015 100
etc.
I want to make a query, where the result is following:
DATE PRICE(TICKER ABC) PRICE(TICKER XYZ)
--------------------------------------------
1.1.2015 50 100
Use PIVOT in SQL SERVER.
DECLARE #test AS TABLE(TICKER VARCHAR(10), DATE DATETIME, SharePrice INT)
INSERT INTO #test
SELECT 'ABC', '1/1/2015', 50 UNION
SELECT 'XYZ', '1/1/2015', 100
SELECT Date, ABC AS [PRICE(TICKER ABC)], XYZ AS [PRICE(TICKER XYZ)] FROM #test
PIVOT(MAX(SharePrice) FOR Ticker IN(ABC, XYZ)) AS A
In TSQL you can write a query using dynamic pivot as:
DECLARE #cols AS NVARCHAR(MAX),#colsFinal AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ', ' + TICKER
from test1
group by TICKER, [DATE]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsFinal = STUFF((SELECT distinct ', isnull( ' + TICKER +
' ,0) as [PRICE (TICKER ' + TICKER +' )]'
from test1
group by TICKER, [DATE]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT [Date],' + #colsFinal + N' from
(
select [Date], TICKER , SharePrice
from test1
) x
pivot
(
max(SharePrice)
for TICKER in (' + #cols + N')
) p '
exec sp_executesql #query;
DEMO