SQL Server Convert Rows Into Columns - sql

I have a table like this with 145.695 rows.
SERVER
TAPE
ACS08
M00030L3
ACS08
M00253L3
ACS09
M00580L3
ACS09
M00602L3
ACS10
M00580L4
ACS10
M00602L5
ACS10
M00602L7
Now I want to reach a target table structure like this:
ACS08
ACS09
ACS10
M00030L3
M00580L3
M00580L4
M00253L3
M00602L3
M00602L5
M00602L7
I need help because I dont know how can I do.

You can use dynamic pivot to get the desired results.
First we need to generate the dynamic columns based on the [SERVER] column values and then pivot the values as per the requirement:
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX);
SET #cols = STUFF((SELECT DISTINCT ','+ QUOTENAME([SERVER])
FROM T FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, ''); --XML way of getting the column values
SET #query = 'SELECT '+#cols+' from
(
SELECT [SERVER], [TAPE], ROW_NUMBER() OVER (PARTITION BY [SERVER] ORDER BY (SELECT NULL)) as RN --We need to add a unique number to select all rows while doing aggregation for the PIVOT
FROM T
)x
PIVOT (max([TAPE]) for [SERVER] in ('+#cols+')
) PVT';
EXECUTE (#query);
Please find the db<>fiddle here.

Try this:
DECLARE #Columns nvarchar(max), #Sql nvarchar(max);
SELECT
#Columns =
STRING_AGG(
'MAX(CASE [Server] WHEN ' + QUOTENAME([Server], '''') + ' THEN [Tape] END) AS ' + QUOTENAME([Server]),
','
) WITHIN GROUP(ORDER BY [Server])
FROM
(
SELECT [Server] FROM T GROUP BY [Server]
) S;
SET #Sql =
'SELECT ' + #Columns + ' FROM
(SELECT [Server], [Tape], ROW_NUMBER() OVER (PARTITION BY [SERVER] ORDER BY [Server]) as RN FROM T) S
GROUP BY RN'
EXEC(#Sql);
Note: STRING_AGG() is supported on SQL Server 2017 and later.

Related

How to make SQL Pivot display more than one row

I was able to display every row in column using pivot however when there are multiple values, it displays only one of the row values. My suspicion lies on the MAX function in the for loop, however, have not been able to find a successful replacement.
I've tried other SQL functions.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(Provincia)
FROM Codigos_Postales
GROUP BY Provincia
ORDER BY Provincia
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET #query = N'SELECT Poblacion,' + #cols + N' from
(
select * from Codigos_Postales
) x
pivot
(
MAX(Codigo_Postal)
for Provincia in (' + #cols + N')
) p ORDER BY Poblacion ASC'
EXEC sp_executesql #query;
Table I'm trying to pivot:
Result:
Expected Result:
If I understand corerctly, adding ROW_NUMBER to your source data will do the trick. The sample PIVOT script will be as below. Just ignore the RN column from your final output, that's it.
SET #query =
N'SELECT Poblacion,' + #cols + N' from
(
SELECT
ROW_NUMBER() OVER (ORDER BY Provincia) RN,
*
FROM Codigos_Postales
) x
PIVOT
(
MAX(Codigo_Postal)
FOR Provincia IN (' + #cols + N')
) p ORDER BY Poblacion ASC'

SELECT inside pivot incorrect

SSMS is highlighting that something is wrong on the line FOR urlsByFilm.Media_Type_ID IN...
BEGIN
SELECT urlsByFilm.Film_ID, urlsByFilm.Media_Type_ID, urlsByFilm.Media_File_Name
FROM [dbo].[Film_Media_Item] urlsByFilm
PIVOT
(
MAX(urlsByFilm.Media_File_Name)
FOR urlsByFilm.Media_Type_ID IN (SELECT DISTINCT Media_Type_ID FROM [dbo].[Film_Media_Item])
) AS pivot
WHERE API_ID in (#API_IDs)
END
I cannot run this, can you help?
you can't have SQL expression in the IN clause, you need to specify the values.
MAX(urlsByFilm.Media_File_Name)
FOR urlsByFilm.Media_Type_ID IN
(SELECT DISTINCT Media_Type_ID FROM [dbo].[Film_Media_Item])
You need to use dynamic SQL to achieve what you are doing.
your query would like this, with dynamic SQL
DECLARE #cols NVARCHAR(2000)
SELECT #cols = STUFF(( SELECT DISTINCT
'],[' + Media_Type_ID
[dbo].[Film_Media_Item]
ORDER BY '],[' + Media_Type_ID
FOR XML PATH('')
), 1, 2, '') + ']'
DECLARE #query NVARCHAR(4000)
SET #query = N'SELECT Media_File_Name, '+
#cols +'
FROM
(SELECT urlsByFilm.Film_ID, urlsByFilm.Media_Type_ID, urlsByFilm.Media_File_Name
FROM [dbo].[Film_Media_Item] urlsByFilm)p
PIVOT
(
MAX(urlsByFilm.Media_File_Name)
FOR urlsByFilm.Media_Type_ID IN ( '+
#cols +' )
) AS pvt
WHERE API_ID in (#API_IDs)'
EXECUTE(#query)

SQL query unknown rows into columns

I asked this question and it was marked as a duplicate of How to pivot unknown number of columns & no aggregate in SQL Server?, but that answer doesn't help me.
I have a table of data that looks like this, with an unknown number of rows and values.
RecID Name Value
1 Color Red
2 Size Small
3 Weight 20lbs
4 Shape Square
I need a query that will return the data like this, building out a column for each row. I cannot hard code anything except the column headers 'Name' and 'Value'.
Color Size Weight Shape
Red Small 20lbs Square
Here is what I have so far that is partly working:
INSERT INTO #Table VALUES
(1,'Color' ,'Red'),
(2,'Size' ,'Small'),
(3,'Weight','20lbs'),
(4,'Shape' ,'Square')
;with mycte
as
(
SELECT rn,cols,val
FROM (SELECT row_number() over(order by Name) rn, Name, Value
FROM #Table) AS src1
UNPIVOT (val FOR cols
IN ( [Name], [Value])) AS unpvt
)
SELECT *
FROM (SELECT rn,cols,val
FROM mycte) AS src2 PIVOT
( Max(val) FOR rn IN ([1], [2], [3])) AS pvt
Which returns:
cols 1 2 3
Name Color Shape Size
Value Red Square Small
Two problems with this that I can't seem to resolve.
I don't need the column headers and the first column that has cols, Name, Value in it.
Can't figure out how to have it build a column for each row without specifying the [x] identifiers.
Any guidance would be great I've been stuck on this a while now.
declare #collist nvarchar(max)
SET #collist = stuff((select distinct ',' + QUOTENAME(name)
FROM #t -- your table here
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
declare #q nvarchar(max)
set #q = '
select *
from (
select rn, name, Value
from (
select *, row_number() over (partition by name order by RecID desc) as rn
from #t -- your table here
) as x
) as source
pivot (
max(Value)
for name in (' + #collist + ')
) as pvt
'
exec (#q)
Until now, I have reached to following code, hope it helps you,
Current outpu comes as
Color Shape Size Weight
Red NULL NULL NULL
NULL NULL Small NULL
NULL NULL NULL 20lbs
NULL Square NULL NULL
Create table DyTable
(
tid int,
Name varchar(20),
Value varchar(20)
)
INSERT INTO DyTable VALUES
(1,'Color' ,'Red'),
(2,'Size' ,'Small'),
(3,'Weight','20lbs'),
(4,'Shape' ,'Square')
DECLARE #Cols NVARCHAR(MAX);
DECLARE #Cols1 NVARCHAR(MAX);
SELECT #Cols = STUFF((
SELECT DISTINCT ', ' + QUOTENAME(Name)
FROM DyTable
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,2,'')
,#Cols1 = STUFF((
SELECT DISTINCT ', max(' + QUOTENAME(Name) + ') as ' + Name
FROM DyTable
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,2,'')
DECLARE #Sql NVARCHAR(MAX)
Select #Cols
SET #Sql = 'Select '+ #Cols1 +'
from (SELECT ' + #Cols + '
FROM DyTable t
PIVOT (MAX(Value)
FOR Name
IN (' + #Cols + ')
)P)a'
EXECUTE sp_executesql #Sql

Dynamic pivot table with multiple columns in sql server

I am trying to pivot table DYNAMICALLY but couldn't get the desired result.
Here is the code to create a table
create table Report
(
deck char(3),
Jib_in float,
rev int,
rev_insight int,
jib_out float,
creation int
)
insert into Report values
('A_1',0.345,0,0,1.23,20140212),
('B_2',0.456,0,4,2.34,20140215),
('C_3',0.554,0,6,0.45,20140217),
('D_4',0.231,0,8,7.98,20140222),
('E_5',0.453,0,0,5.67,20140219),
('F_6',0.344,0,3,7.23,20140223)'
Code written so far.... this pivots the column deck and jib_in into rows but thats it only TWO ROWS i.e the one i put inside aggregate function under PIVOT function and one i put inside QUOTENAME()
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME(deck)
FROM (SELECT p.deck FROM dbo.report AS p
GROUP BY p.deck) AS x;
SET #sql = N'
SELECT ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT p.deck, p.jib_in
FROM dbo.report AS p
) AS j
PIVOT
(
SUM(jib_in) FOR deck IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;';
PRINT #sql;
EXEC sp_executesql #sql;
I need all the columns to be pivoted and show on the pivoted table. any help would be appreciated. I am very new at dynamic pivot. I tried so many ways to add other columns but no avail!!
I know there are other ways please feel free to mention if there is any other way to get this right.
Please use this (If you are getting Collation issue, please change all the 3 INT datatypes):
STATIC code:
SELECT HEADER, [A_1],[B_2],[C_3],[D_4],[E_5],[F_6]
FROM
(SELECT DECK,HEADER, VALUE FROM REPORT
UNPIVOT
(
VALUE FOR HEADER IN ([JIB_IN],[REV],[REV_INSIGHT],[JIB_OUT],[CREATION])
) UNPIV
) SRC
PIVOT
(
SUM(VALUE)
FOR DECK IN ([A_1],[B_2],[C_3],[D_4],[E_5],[F_6])
) PIV
Using Dynamic SQL:
DECLARE #COLSUNPIVOT AS NVARCHAR(MAX),
#QUERY AS NVARCHAR(MAX),
#COLSPIVOT AS NVARCHAR(MAX)
SELECT #COLSUNPIVOT = STUFF((SELECT ','+QUOTENAME(C.NAME)
FROM SYS.COLUMNS AS C
WHERE C.OBJECT_ID = OBJECT_ID('REPORT') AND C.NAME <> 'DECK'
FOR XML PATH('')), 1, 1, '')
SELECT #COLSPIVOT = STUFF((SELECT ',' + QUOTENAME(DECK)
FROM REPORT T FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SET #QUERY
= 'SELECT HEADER, '+#COLSPIVOT+'
FROM
(
SELECT DECK,HEADER,VALUE FROM REPORT
UNPIVOT
(
VALUE FOR HEADER IN ('+#COLSUNPIVOT+')
) UNPIV
) SRC
PIVOT
(
SUM(VALUE)
FOR DECK IN ('+#COLSPIVOT+')
) PIV'
EXEC(#QUERY)

select from the result of execute(#query)

I am using this SQL query
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Animal2)
from animals
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Animal1, ' + #cols + ' from
(
select animal1, animal2, Corelation
from animals
) x
pivot
(
min(Corelation)
for animal2 in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with demo
When I execute the query I get a table as a return.
How can I select from that table? I tried to use SELECT * FROM (*past here the script*) but it did not work. I just need to use the result of the execute(#query) as a table and select from it (to put it in a new table). How can I do it?
Thanks
NOTE: that query was an answer of this SO question
Use the Insert into ... exec format, like this:
CREATE TABLE #tmp1 (
[Animal1] varchar(5),
[Cat] decimal(10, 5),
[Dog] decimal(10, 5),
[Mouse] decimal(10, 5)
)
Insert Into #Tmp1
execute(#query)
select * from #tmp1
where cat = 1
Of course, since the column names are dynamic, you'll need to shift the create statement to dynamic sql too.
SQL Fiddle with the fixed version
SQL Fiddle with the dynamic version
Use into and a global temporary table - then you don't have to define the table columns in advance.
set #query = 'SELECT Animal1, ' + #cols +
+' into ##temp '
+' from
(
select animal1, animal2, Corelation
from animals
) x
pivot
(
min(Corelation)
for animal2 in (' + #cols + ')
) p '
select * from ##temp