I'm trying to do a PIVOT on a table with two rows like this:
Category | Sector
---------------------------
Bulbs | DIY
Bulbs | Home
Picnic blanket | DIY
Picnic blanket | Home
Picnic blanket | Interior
Each category can have 1 or more sectors.
I'm trying to get a table like this:
Category | Sector 1 | Sector 2 | Sector 3
-------------------------------------------------
Bulbs | DIY | Home | NULL
Picnic blanket | DIY | Home | Interior
The query looks like this:
SELECT
dbo.fn_DbContent_GetTranslation(pt.Name_DbContentId, 2) 'Category'
, dbo.fn_DbContent_GetTranslation(s.Name_DbContentId, 2) 'Sector'
FROM dbo.ProductType pt
JOIN dbo.ProductTypeMandator ptm ON ptm.ProductTypeId = pt.Id
JOIN dbo.ProductTypeMandator2PortalSector ptmps ON ptmps.ProductTypeMandatorId = ptm.Id
JOIN dbo.PortalSector ps ON ps.Id = ptmps.PortalSectorId
JOIN dbo.Sector s ON s.Id = ps.SectorId
WHERE
ptmps.PortalSectorId IN (21, 18, 19)
I already did a PIVOT but with a table containing three columns where one contained the values for the headers in the pivot table. In this case the values for the header are missing so I don't know how to do it then.
Thanks for helping
You can solve it that way:
-- Create demo data
CREATE TABLE #cats(category nvarchar(25), sector nvarchar(25))
INSERT INTO #cats(category, sector)
VALUES (N'Bulbs',N'DIY'),
(N'Bulbs',N'Home'),
(N'Picnic blanket',N'DIY'),
(N'Picnic blanket',N'Home'),
(N'Picnic blanket',N'Interior')
SELECT *
FROM (
SELECT category, sector
FROM #cats
) as dat
PIVOT(
MAX(sector)
FOR sector IN([DIY],[Home],[Interior])
) as pvt
-- Cleanup
DROP TABLE #cats
If you want it to be named correctly as in your example, you can combine it with a named numbering:
-- Create demo data
CREATE TABLE #cats(category nvarchar(25), sector nvarchar(25))
INSERT INTO #cats(category, sector)
VALUES (N'Bulbs',N'DIY'),
(N'Bulbs',N'Home'),
(N'Picnic blanket',N'DIY'),
(N'Picnic blanket',N'Home'),
(N'Picnic blanket',N'Interior')
SELECT *
FROM (
SELECT category, sector, N'Sector '+CONVERT(nvarchar(max),DENSE_RANK() OVER(ORDER BY sector)) as rn
FROM #cats
) as dat
PIVOT(
MAX(sector)
FOR rn IN([Sector 1],[Sector 2],[Sector 3])
) as pvt
-- Cleanup
DROP TABLE #cats
And last but not least, if you want it to be dynamical:
-- Create demo data
CREATE TABLE #cats(category nvarchar(25), sector nvarchar(25))
INSERT INTO #cats(category, sector)
VALUES (N'Bulbs',N'DIY'),
(N'Bulbs',N'Home'),
(N'Picnic blanket',N'DIY'),
(N'Picnic blanket',N'Home'),
(N'Picnic blanket',N'Interior')
DECLARE #sql nvarchar(max), #cols nvarchar(max)
-- get proper column list
SELECT #cols = COALESCE(#cols + N',[' + grCols.rn + N']',N'[' + grCols.rn + N']')
FROM (
SELECT DISTINCT N'Sector '+CONVERT(nvarchar(max),DENSE_RANK() OVER(ORDER BY sector)) as rn
FROM #cats
) as grCols
SET #sql = N'
SELECT *
FROM (
SELECT category, sector, N''Sector ''+CONVERT(nvarchar(max),DENSE_RANK() OVER(ORDER BY sector)) as rn
FROM #cats
) as dat
PIVOT(
MAX(sector)
FOR rn IN('+#cols+')
) as pvt'
EXEC(#sql)
-- Cleanup
DROP TABLE #cats
You can do this in two ways,
One is Conditional Aggregate
;WITH cte
AS (SELECT *,
rn=Row_number()
OVER(
partition BY category
ORDER BY (SELECT NULL))
FROM yourtable)
SELECT category,
[sector 1] = Max(CASE WHEN rn = 1 THEN sector END),
[sector 2] = Max(CASE WHEN rn = 2 THEN sector END),
[sector 3] = Max(CASE WHEN rn = 3 THEN sector END)
FROM cte
GROUP BY category
Another way is using Pivot
SELECT *
FROM (SELECT *,
sector_col = 'sector '
+ Cast(Row_number()OVER(partition BY category ORDER BY (SELECT NULL)) AS VARCHAR(20))
FROM yourtable) A
PIVOT (Max(sector)
FOR sector_col IN ([sector 1],
[sector 2],
[sector 3])) piv
Note : As mentioned in comments if the sector values are not static or unknown then you may have convert the same to dynamic query
Related
I have a table Occupation like such:
Name | Occupation
-----------------
Sam | Doctor
Joe | Professor
John | Actor
Hailey | Singer
April | Doctor
My goal is to utilize the PIVOT function to display each distinct Occupation as their own column like so:
Doctor | Professor | Singer | Actor
-----------------------------------
Sam | Joe | Hailey | John
April
I went through various stack overflow questions with similar issues, and even utilized the documentation here and followed step by step. My efforts have been futile, so what gives? I am receiving a syntax error every time I run this code. Any suggestions?
Code:
SELECT *
FROM(SELECT Name, Occupation from Occupations) as src
PIVOT
(MAX(Name) FOR Name IN [Doctor], [Professor], [Singer], [Actor]) as piv;
I am solving this problem on Hackerrank, and the compiler was MySQL. I changed it to MSSQL and am no longer receiving a syntax error.
You were missing 2 () One on each side in the PIVOT part, I bolded the brackets I added:
([Doctor], [Professor], [Singer], [Actor]) - These 2
SELECT *
FROM (
SELECT Name, Occupation
FROM Occupations
) as src
PIVOT
(
MAX(Name) FOR Name IN ([Doctor], [Professor], [Singer], [Actor])
) as piv;
This query will generate the answer as per the way you need. The above answer does not provide the answer as the way you required. Try this answer.
DECLARE #sql NVARCHAR(MAX) = N''
DECLARE #cols NVARCHAR(MAX) = N''
--Making the column list dynamically
SELECT #cols = STUFF((SELECT DISTINCT ', '+QUOTENAME( [T2].[Occupation])
FROM Occupation_data [T2]
FOR XML PATH('')), 1, 1, '')
--preparing PIVOT query dynamically.
SET #SQL = ' SELECT
*
into #temp
FROM
(
SELECT row_number() over (order by name) as id, [Name], [Occupation]
FROM Occupation_data
) AS cp
PIVOT
(
min([Name]) FOR [Occupation] IN (' + #cols + ')
) AS up;
Select
row_number() over (order by doctor asc ) as id1
,*
into #temp_1
from #temp where Doctor is not null
Select
row_number() over (Order by Actor asc ) as id2
,*
into #temp_2
from #temp where Actor is not null
Select
row_number() over (Order by Professor asc ) as id3
,*
into #temp_3
from #temp where Professor is not null
Select
row_number() over (Order by Singer asc ) as id4
,*
into #temp_4
from #temp where Singer is not null
select
A.Doctor
,B.Actor
,C.Professor
,D.Singer
from
#temp_1 A inner join
#temp_2 B ON A.id1 = B.id2
INNER JOIN
#temp_3 C ON A.id1 = C.id3
INNER JOIN
#temp_4 D ON A.id1 = d.id4
drop table #temp
drop table #temp_1
drop table #temp_2
drop table #temp_3
drop table #temp_4
';
PRINT( #SQL)
EXEC (#SQL)
Output:
If this answer works for you I will make it more generic and give you so that you can apply this for any work like this.
I using SQL Server 2008 R2 / 2014. I wish to find a SQL query that can do the following:
Rules:
Each [Group] must have [Number] 1 to 6 to be complete group.
[Name] in each [Group] must be unique.
Each row only can use 1 time.
Table before sorting is...
Name Number Group
---- ------ -----
A 1
B 6
A 123
C 3
B 4
C 23
D 45
D 4
C 56
A 12
D 56
After sorting, result I want is below or similar....
Name Number Group
---- ------ -----
A 1 1
C 23 1
D 45 1
B 6 1
A 123 2
D 4 2
C 56 2
A 12 3
C 3 3
B 4 3
D 56 3
What I tried before is to find a subgroup that have [Number] consist of 1-6 with below concatenate method...
SELECT *
FROM [Table1] ST2
WHERE
SUBSTRING((SELECT ST1.[Number] AS [text()]
FROM [Table1] ST1
-- WHERE ST1.[Group] = ST2.[Group]
ORDER BY LEFT(ST1.[Number],1)
FOR XML PATH ('')), 1, 1000) = '123456'
Maybe you should check ROW_NUMBER function.
select Name
, Number
, ROW_NUMBER () OVER(PARTITION BY Name ORDER BY Number) as Group
from [Table1]
If you have more than 6 rows with same NAME value then it will return more groups. You can filter additional groups out since you are interested in only 6 groups with unique values of NAME column.
I'm not sure if this can be done more simply or not, but here's my go at it...
Advanced warning, this requires some means of splitting strings. Since you're not on 2016, I've included a function at the beginning of the script.
The bulk of the work is a recursive CTE that builds the Name and Number columns into comma delimited groups. We then reduce our working set to only the groups where the numbers would create 123456, split the groups and use ROW_NUMBER() OVER... to identify them, and then select based on the new data.
Demo: http://rextester.com/NEXG53500
CREATE FUNCTION [dbo].[SplitStrings]
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
CREATE TABLE #temp
(
name VARCHAR(MAX),
number INT
)
INSERT INTO #temp
VALUES
('a',1),
('b',6),
('a',123),
('c',3),
('b',4),
('c',23),
('d',45),
('d',4),
('c',56),
('a',12),
('d',56);
/*** Recursively build groups based on information from #temp ***/
WITH groupFinder AS
(
SELECT CAST(name AS VARCHAR(MAX)) AS [groupNames], CAST(number AS VARCHAR(max)) AS [groupNumbers] FROM #temp
UNION ALL
SELECT
cast(CONCAT(t.[Name],',',g.[groupNames]) as VARCHAR(MAX)),
CAST(CONCAT(CAST(t.[Number] AS VARCHAR(max)),',',CAST(g.[groupNumbers] AS VARCHAR(max))) AS VARCHAR(max))
FROM #temp t
JOIN groupFinder g
ON
g.groupNames NOT LIKE '%' + t.name+'%'
AND g.[groupNumbers] NOT LIKE '%' + CAST(t.number/100 AS VARCHAR(10)) +'%'
AND g.[groupNumbers] NOT LIKE '%' + CAST(t.number/10 AS VARCHAR(10)) +'%'
AND g.[groupNumbers] NOT LIKE '%' + CAST(t.number%10 AS VARCHAR(10)) +'%'
)
/*** only get groups where the numbers form 123456 ***/
, groupPruner AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY [groupNames]) AS [rn] FROM groupFinder WHERE REPLACE([groupNumbers],',','') = '123456'
)
/*** split the name group and give it identifiers ***/
, nameIdentifier AS
(
SELECT g.*, c1.[item] AS [Name], ROW_NUMBER() OVER (PARTITION BY [rn] ORDER BY (SELECT NULL)) AS [rn1]
FROM groupPruner g
CROSS APPLY splitstrings(g.groupnames,',') c1
)
/*** split the number group and give it identifiers ***/
, numberIdentifier AS
(
SELECT g.*, c1.[item] AS [Number], ROW_NUMBER() OVER (PARTITION BY [rn], [rn1] ORDER BY (SELECT NULL)) AS [rn2]
FROM nameIdentifier g
CROSS APPLY splitstrings(g.groupNumbers,',') c1
)
SELECT [Name], [Number], [rn] AS [Group]
--,groupnames, groupNumbers /*uncomment this line to see the groups that were built*/
FROM numberIdentifier
WHERE rn1 = rn2
ORDER BY rn, rn1
DROP TABLE #temp
I have a table where every ID has one or more places, and each place comes with a count. Places can be repeated within IDs. It is stored in rows like so:
ID ColumnName DataValue
1 place1 ABC
1 count1 5
2 place1 BEC
2 count1 12
2 place2 CDE
2 count2 6
2 place3 BEC
2 count3 9
3 place1 BBC
3 count1 5
3 place2 BBC
3 count2 4
Ultimately, I want a table where every possible place name is its own column, and the count per place per ID is summed up, like so:
ID ABC BEC CDE BBC
1 5 0 0 0
2 0 21 6 0
3 0 0 0 9
I don't know the best way to go about this. There are around 50 different possible place names, so specifically listing them out in a query isn't ideal. I know I ultimately have to pivot the data, but I don't know if I should do it before or after I sum up the counts. And whether it's before or after, I haven't been able to figure out how to go about summing it up.
Any ideas/help would be greatly appreciated. At this point, I'm having a hard time finding where to even start. I've seen a few posts with similar problems, but nothing quite as convoluted as this.
EDIT:
Right now I'm working with this to pivot the table, but this leaves me with columns named place1, place2, .... count1, count2,...
and I don't know how to appropriately sum up the counts and make new columns with the place names.
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX);
SET #cols = STUFF(
(
SELECT DISTINCT
','+QUOTENAME(c.[ColumnName])
FROM #temp c FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '');
SET #query = 'SELECT [ID], '+#cols+'from (SELECT [ID],
[DataValue] AS [amount],
[ColumnName] AS [category]
FROM #temp
)x pivot (max(amount) for category in ('+#cols+')) p';
EXECUTE (#query);
Your table structure is pretty bad. You'll need to normalize your data before you can attempt to pivot it. Try this:
;WITH IDs AS
(
SELECT DISTINCT
id
,ColId = RIGHT(ColumnName, LEN(ColumnName) - 5)
,Place = datavalue
FROM #temp
WHERE ISNUMERIC(datavalue) = 0
)
,Counts AS
(
SELECT DISTINCT
id
,ColId = RIGHT(ColumnName, LEN(ColumnName) - 5)
,Cnt = CAST(datavalue AS INT)
FROM #temp
WHERE ISNUMERIC(datavalue) = 1
)
SELECT
piv.id
,ABC = ISNULL(piv.ABC, 0)
,BEC = ISNULL(piv.BEC, 0)
,CDE = ISNULL(piv.CDE, 0)
,BBC = ISNULL(piv.BBC, 0)
FROM (SELECT i.id, i.Place, c.Cnt FROM IDs i JOIN Counts c ON c.id = i.id AND c.ColId = i.ColId) src
PIVOT ( SUM(Cnt)
FOR Place IN ([ABC], [BEC], [CDE], [BBC])
) piv;
Doing it with dynamic SQL would yield the following:
SET #query =
';WITH IDs AS
(
SELECT DISTINCT
id
,ColId = RIGHT(ColumnName, LEN(ColumnName) - 5)
,Place = datavalue
FROM #temp
WHERE ISNUMERIC(datavalue) = 0
)
,Counts AS
(
SELECT DISTINCT
id
,ColId = RIGHT(ColumnName, LEN(ColumnName) - 5)
,Cnt = CAST(datavalue AS INT)
FROM #temp
WHERE ISNUMERIC(datavalue) = 1
)
SELECT [ID], '+#cols+'
FROM
(
SELECT i.id, i.Place, c.Cnt
FROM IDs i
JOIN Counts c ON c.id = i.id AND c.ColId = i.ColId
) src
PIVOT
(SUM(Cnt) FOR Place IN ('+#cols+')) piv;';
EXECUTE (#query);
Try this out:
SELECT id,
COALESCE(ABC, 0) AS ABC,
COALESCE(BBC, 0) AS BBC,
COALESCE(BEC, 0) AS BEC,
COALESCE(CDE, 0) AS CDE
FROM
(SELECT id,
MIN(CASE WHEN columnname LIKE 'place%' THEN datavalue END) AS col,
CAST(MIN(CASE WHEN columnname LIKE 'count%' THEN datavalue END) AS INT) AS val
FROM t
GROUP BY id, RIGHT(columnname, 1)
) src
PIVOT
(SUM(val)
FOR col in ([ABC], [BBC], [BEC], [CDE])) pvt
Tested here: http://rextester.com/XUTJ68690
In the src query, you need to re-format your data, so that you have a unique id and place in each row. From there a pivot will work.
If the count is always immediately after the place, the following query will generate a data set for pivoting.
The result data set before pivoting has the following columns:
id, placename, count
select placeTable.id, placeTable.datavalue, countTable.datavalue
from
(select *, row_number() over (order by id, %%physloc%%) as rownum
from test
where isnumeric(datavalue) = 1
) as countTable
join
(select *, row_number() over (order by id, %%physloc%%) as rownum
from test
where isnumeric(datavalue) <> 1
) as placeTable
on countTable.id = placeTable.id and
countTable.rownum = placeTable.rownum
Tested on sqlfidde mssqlserver: http://sqlfiddle.com/#!6/701c91/18
Here is one other approach using PIVOT operator with dynamic style
declare #Col varchar(2000) = '',
#Query varchar(2000) = ''
set #Col = stuff(
(select ','+QUOTENAME(DataValue)
from table where isnumeric(DataValue) = 0
group by DataValue for xml path('')),1,1,'')
set #Query = 'select id, '+#Col+' from
(
select id, DataValue,
cast((case when isnumeric(DataValue) = 1 then DataValue else lead(DataValue) over (order by id) end) as int) Value
from table
) as a
PIVOT
(
sum(Value) for DataValue in ('+#Col+')
)pvt'
EXECUTE (#Query)
Note : I have used lead() function to access next rows data if i found character string values and replace with numeric data values
Result :
id ABC BBC BEC CDE
1 5 NULL NULL NULL
2 NULL NULL 21 6
3 NULL 9 NULL NULL
I am using an SQL Server database and have these following tables
Table "Data"
--------------------------------------------------------------------------------------------------|
| Id |col_1_type | col_1_name | col_2_type | col_2_name | col_3_type | col_3_name |
--------------------------------------------------------------------------------------------------|
| 1 |KI | Inflation Rate | KI | Currency Rate | MI | Government Spending |
--------------------------------------------------------------------------------------------------|
And i just want to make my result to be like this:
+----+------------------------+
| Id | results |
+----+------------------------+
| 1 | KI-Inflation Rate |
| 2 | KI-Currency Rate |
| 3 | MI-Government Spending |
+----+------------------------+
The column name is mandatory though, thats what made it complicated i guess?
i know you can merge 2 values or concatenate it, but i'm stuck on the column name such as col_1_name and col_2_type. Do i need to use regexp maybe?
Please try this-
select ROW_NUMBER() OVER (ORDER BY (select null)) id , results
from
(
SELECT CONCAT(col_1_type,'-',col_1_name) results
FROM [Data]
UNION ALL
SELECT CONCAT(col_2_type,'-',col_2_name)
FROM Data
UNION ALL
SELECT CONCAT(col_3_type,'-',col_3_name)
FROM Data
)o
Or this also
SELECT Id,results
FROM Data
CROSS apply
(VALUES (CONCAT(col_1_type,'-',col_1_name),1),(CONCAT(col_2_type,'-',col_2_name),2)
,(CONCAT(col_3_type,'-',col_3_name) ,3) ) cs (results,Id)
I would use of cross apply with the help of CTE and stuff()
;with cte as
(
select a.* from table t
cross apply (
values
(t.col_1_type, 'col_1'),
(t.col_1_name, 'col_1'),
(t.col_2_type, 'col_2'),
(t.col_2_name, 'col_2'),
(t.col_3_type, 'col_3'),
(t.col_3_name, 'col_3')
) a(name, id)
)
select distinct stuff(
(select '-'+name from cte where id= c.id for xml path('')),
1,1, ''
) [Results],
from cte c
EDIT :
Not sure about Id column but my guess that could be resolved by using ranking function
select row_number() over (order by (select 1)) Id,
cc.Results from
(
select distinct stuff(
(select '-'+id from cte where name = c.name for xml path('')),
1,1, ''
) [Results]
from cte c
) cc
Result :
Id Results
1 KI-Currency Rate
2 KI-Inflation Rate
3 MI-Government Spending
Sample data
IF OBJECT_ID('tempdb..#t') iS NOT NULL
DROP TABLE #t
IF OBJECT_ID('dbo.temp','U') iS NOT NULL
DROP TABLE temp
;With CTe(
Id ,col_1_type , col_1_name, col_2_type , col_2_name, col_3_type , col_3_name )
AS
(
SELECT 1,'KI','Inflation Rate','KI','Currency Rate','MI','Government Spending'
)
SELECT * INTO temp FROM CTe
Using Dynamic sql
DECLARE #Sqlstring nvarchar(max)
,#SQlQuery nvarchar(max)
;WITH cte
AS
(
SELECT COLUMN_NAME ,
((ROW_NUMBER()OVER(ORDER BY (SELECT NULL))-1)/2 )+1 AS BatchSeq
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='temp' AND COLUMN_NAME<>'Id'
)
SELECT #Sqlstring=STUFF((SELECT ', '+COLUMN_NAME FROM
(
SELECT DISTINCT '('+STUFF((SELECT ', '+COLUMN_NAME
FROM cte i
WHERE i.BatchSeq=o.BatchSeq FOR XML PATH ('')),1,1,'') +')' AS COLUMN_NAME
FROM cte o
)dt
FOR XML PATH ('')),1,1,'')
SET #SQlQuery='
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS ID,
CONCAT(col_type,''-'',Col_names) AS Result
FROM Temp
CROSS APPLY ( VALUES '+#Sqlstring+') dt(col_type,Col_names)'
PRINT #SQlQuery
EXEC(#SQlQuery)
Result
ID Result
-----------------------
1 KI-Inflation Rate
2 KI-Currency Rate
3 MI-Government Spending
Try like this
select (column1 || ' '|| column2) from table;
or
SELECT tablename.col_1_type + ' ' + tablename.col_1_name AS results;
I have a table like
ID option
1 optionA
1 optionB
1 optionC
1 optionD
And I want a result like:
ID A B C D
1 optionA optionB optionC optionD
What is the best way to do this?
Query which i have tried is
select * from TableName PIVOT (option for ID = 2674 )) as abc
this will not work since PIVOT expects aggregated function..
I have also tried COALESCE like this
declare #t table(num VARCHAR(100))
insert into #t
select choice FROM QuestionAnswers where QuestionID=2674
select num from #t
declare #s varchar(8000)
select #s = COALESCE(#s + ',', '') + num
from #t
exec('select '+#s)
but this doesn't work as well..
This type of data transformation is known as a pivot. In SQL Server 2005+ there is a function that will perform this data rotation for you. However, there are many ways that you can perform this data transformation.
Here is a PIVOT query that will work with your sample data:
select *
from
(
select id, [option], right([option], 1) col
from yourtable
) src
pivot
(
max([option])
for col in (a, b, c, d)
) piv
See SQL Fiddle with Demo.
This can also be performed using an aggregate function with a CASE expression:
select id,
max(case when col = 'a' then [option] else null end) a,
max(case when col = 'b' then [option] else null end) b,
max(case when col = 'c' then [option] else null end) c,
max(case when col = 'd' then [option] else null end) d
from
(
select id, [option], right([option], 1) col
from yourtable
) src
group by id
See SQL Fiddle with Demo.
You can perform multiple joins on your table:
select a.id,
a.[option] a,
b.[option] b,
c.[option] c,
d.[option] d
from yourtable a
left join yourtable b
on a.id = b.id
and right(b.[option], 1) = 'b'
left join yourtable c
on a.id = c.id
and right(c.[option], 1) = 'c'
left join yourtable d
on a.id = d.id
and right(d.[option], 1) = 'd'
where right(a.[option], 1) = 'a'
See SQL Fiddle with Demo
Lastly, this can be done using dynamic sql if the values to be turned into columns is unknown:
DECLARE #colsName AS NVARCHAR(MAX),
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsName = STUFF((SELECT distinct ', ' + QUOTENAME(right([option], 1)) +' as '+ right([option], 1)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #cols = STUFF((SELECT distinct ', ' + QUOTENAME(right([option], 1))
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT id, ' + #colsName + ' from
(
select id, [option], right([option], 1) col
from yourtable
) x
pivot
(
max([option])
for col in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
The result of all queries is:
| ID | A | B | C | D |
----------------------------------------------
| 1 | optionA | optionB | optionC | optionD |
CREATE TABLE Product(Cust VARCHAR(25), Product VARCHAR(20), QTY INT)
GO
-- Inserting Data into Table
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','VEG',2)
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','SODA',6)
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','MILK',1)
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','BEER',12)
INSERT INTO Product(Cust, Product, QTY)
VALUES('FRED','MILK',3)
INSERT INTO Product(Cust, Product, QTY)
VALUES('FRED','BEER',24)
INSERT INTO Product(Cust, Product, QTY)
VALUES('KATE','VEG',3)
GO
-- Selecting and checking entires in table
SELECT *
FROM Product
GO
-- Pivot Table ordered by PRODUCT
SELECT PRODUCT, FRED, KATE
FROM (
SELECT CUST, PRODUCT, QTY
FROM Product) up
PIVOT (SUM(QTY) FOR CUST IN (FRED, KATE)) AS pvt
ORDER BY PRODUCT
GO
-- Pivot Table ordered by CUST
SELECT CUST, VEG, SODA, MILK, BEER, CHIPS
FROM (
SELECT CUST, PRODUCT, QTY
FROM Product) up
PIVOT (SUM(QTY) FOR PRODUCT IN (VEG, SODA, MILK, BEER, CHIPS)) AS pvt
ORDER BY CUST
GO
-- Unpivot Table ordered by CUST
SELECT CUST, PRODUCT, QTY
FROM
(
SELECT CUST, VEG, SODA, MILK, BEER, CHIPS
FROM (
SELECT CUST, PRODUCT, QTY
FROM Product) up
PIVOT
( SUM(QTY) FOR PRODUCT IN (VEG, SODA, MILK, BEER, CHIPS)) AS pvt) p
UNPIVOT
(QTY FOR PRODUCT IN (VEG, SODA, MILK, BEER, CHIPS)
) AS Unpvt
GO
-- Clean up database
DROP TABLE Product
GO
Ref http://blog.sqlauthority.com/2008/06/07/sql-server-pivot-and-unpivot-table-examples/
Edited
DECLARE #Product TABLE (ID int, _option varchar(10) )
-- Inserting Data into Table
INSERT INTO #Product
(
ID,
_option
)
SELECT 1, 'optionA' UNION ALL
SELECT 1, 'optionB' UNION ALL
SELECT 1, 'optionC' UNION ALL
SELECT 1, 'optionD'
SELECT
optionA, optionB, optionC, optionD
FROM (
SELECT ID, _option
FROM #Product) up
PIVOT (SUM(ID) FOR _option IN (optionA, optionB, optionC, optionD)) AS pvt