how to transpose rows in SQL - sql

I have a table named "TABLE1" Need output in below format. How can I use pivot in this case or any Inner joins to get output

You can use dynamic SQL with pivoting like below:
CREATE TABLE TABLE1 (
Code nvarchar(1),
Ind nvarchar(3),
Region nvarchar(10),
Amt decimal(17,7),
Currency nvarchar(3),
Aging nvarchar(6),
[Count] int
)
--create table with data you provided
INSERT INTO TABLE1 VALUES
('X','XYZ','Region1', 16882.96585, 'INR','0-30', 3),
('X','XYZ','Region2', 30831.0445, 'INR','31-60', 3),
('X','XYZ','Region3', 8759.319245, 'INR','61-90', 1),
('X','XYZ','Region4', 39070.18077, 'INR','91-180', 1)
DECLARE #sql nvarchar(max),
#col nvarchar(max)
--here we join all column names we need with aging values
SELECT #col = (
SELECT ','+QUOTENAME([name]+' ('+Aging+')')
FROM TABLE1 t
CROSS JOIN sys.columns c
WHERE [object_id] = OBJECT_ID(N'TABLE1') AND column_id > 2 AND [name] != 'Aging'
FOR XML PATH('')
)
--construction of dynamic query
SELECT #sql = N'
SELECT *
FROM (
SELECT Code,
Ind,
[Columns]+'' (''+Aging+'')'' as [Columns],
[Values]
FROM (
SELECT Code,
Ind,
CAST(Region as nvarchar(max)) Region,
CAST(Amt as nvarchar(max)) Amt,
CAST(Currency as nvarchar(max)) Currency,
CAST(Aging as nvarchar(max)) Aging,
CAST([Count] as nvarchar(max)) [Count],
ROW_NUMBER() OVER (PARTITION BY Code ORDER BY Aging) as RowNum
FROM TABLE1
) as t
UNPIVOT (
[Values] FOR [Columns] IN (Region, Amt, Currency, [Count])
) as unp
) as d
PIVOT (
MAX([Values]) FOR [Columns] IN ('+STUFF(#col,1,1,'')+')
) as pvt'
EXEC sp_executesql #sql
DROP TABLE TABLE1
Output:
Code Ind Region (0-30) Amt (0-30) Currency (0-30) Count (0-30) Region (31-60) Amt (31-60) Currency (31-60) Count (31-60) Region (61-90) Amt (61-90) Currency (61-90) Count (61-90) Region (91-180) Amt (91-180) Currency (91-180) Count (91-180)
X XYZ Region1 16882.9658500 INR 3 Region2 30831.0445000 INR 3 Region3 8759.3192450 INR 1 Region4 39070.1807700 INR 1
Hope this helps.
If the structure of the query won't vary, you can PRINT #sql and then use the query for your needs, without dynamic SQL.

Related

How to convert row to column in my case using SQL Server? [duplicate]

This question already has answers here:
How to pivot without knowing fixed columns in T-SQL
(3 answers)
Closed 2 years ago.
I need to convert a row to a column, I never worked on in this scenario.
Product
ProdID Price
---------------
111 52.5
111 50.5
112 40
111 65
Expected results:
ProdID Price1 Price2 Price3
------------------------------------
111 52.5 50.5 65
112 40
Note
I have no idea how many prices will be there for the same item. Sometimes it will be only one, sometimes 2 or 5.
So based on that it has to create the column.
I saw a lot of posts only converting the exact column, not for a dynamic column like my scenario.
Demo on db<>fiddle
You need to use Dynamic SQL PIVOT like https://stackoverflow.com/a/60331153
Use ROW_NUMBER() combines with CONCAT() to mark dynamic column like Price1, Price2, Price3, etc.
DECLARE
#columns NVARCHAR(MAX) = '',
#sql NVARCHAR(MAX) = '';
SELECT ProdID, Price, Col = CONCAT('Price', ROW_NUMBER() OVER (PARTITION BY ProdID ORDER BY ProdID))
into #b
FROM #a
SELECT #columns += QUOTENAME(Col) + ','
from (SELECT DISTINCT Col FROM #b) A
-- remove the last comma
SET #columns = LEFT(#columns, LEN(#columns) - 1);
SET #sql = 'SELECT * FROM ( SELECT ProdID, Price, Col FROM #b) src PIVOT( MAX([Price]) FOR Col IN ('+ #columns +')) AS pivot_table;';
-- execute the dynamic SQL
EXECUTE sp_executesql #sql;
Output
Create table ItemDetails
(
prodid numeric(10),
price numeric(10,2),
orderno int identity(1,1)
)
declare #pricecols varchar(max)='',
#pricecolName nvarchar(max)='',
#statement nvarchar(4000)=''
select #pricecolName= stuff(
(
select ','+pricecol from (
select distinct 'price'+convert(varchar(10),(row_number() over(partition by prodid order by orderno)))
pricecol FROM ItemDetails ) as tbl
for xml path('')),1,1,'')
set #statement= 'select prodID,'+#pricecolName+' from (
select prodid,price,''price''+convert(varchar(10),(row_number()
over(partition by prodid order by orderno))) as
pricecol FROM ItemDetails
) [itemPrice]
pivot
(
max(price)
for pricecol
in ('+#pricecolName+') ) as pivatetble'
exec sp_executesql #statement
OutPut- (note: price value duplicated for Item2 [112])1

convert rows as column (like PIVOT) is not working if the number of values increases in SQL Server

I want to convert rows as column (like PIVOT) and i am unable to get if the number of values increases.
Below is my table.
i want the output like this.
I have used the following queries to acheive this but no luck.
Query1
Create table #temp(instanceid int, submissionid int, name1 varchar(20), value1 varchar(20))
insert into #temp(instanceid,submissionid,name1,value1)
Select 5151,5532,'Question_1','Y'
union
Select 5151,5532,'First','Mujda'
union
Select 5151,5532,'Last','Zhublawar'
union
Select 5151,5532,'Question_1','Y'
union
Select 5151,5532,'First','Mujda1'
union
Select 5151,5532,'Last','Zhublawar1'
union
Select 5151,5532,'Question_1','Y'
union
Select 5152,5533,'First','Muthu'
union
Select 5151,5533,'Last','Kumar'
union
Select 5152,5533,'Question_1','Y'
union
Select 5152,5533,'First','Muthu1'
union
Select 5152,5533,'Last','Kumar1'
GO
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
DECLARE #PivotValues AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME(seq)
FROM (
select (cast(row_number() over(partition by name1 order by name1) as varchar(10)) + name1) as seq
from #temp group by value1,name1,instanceid
) AS PivotExample
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N'SELECT instanceid,submissionid, ' + #PivotColumns + '
FROM #temp
PIVOT( MAX(value1)
FOR name1 IN (' + #PivotColumns + ')) AS P'
--Execute dynamic query
EXEC sp_executesql #SQLQuery
DROP TABLE #temp
Query2:
Create table #temp(instanceid int, submissionid int, name1 varchar(20), value1 varchar(20))
insert into #temp(instanceid,submissionid,name1,value1)
Select 5151,5532,'Question_1','Y'
union
Select 5151,5532,'First','Mujda'
union
Select 5151,5532,'Last','Zhublawar'
union
Select 5151,5532,'Interest','100'
select * from(
Select
instanceid,
submissionid,
[1st Ownership First Name] = Case when name1='First' then value1 end,
[1st Ownership Last Name] = Case when name1='Last' then value1 end,
[1st Ownership Question] = Case when name1='Question_1' then value1 end
from #temp
group by instanceid,submissionid,name1,value1
) P where p.[1st Ownership First Name] is not null or p.[1st Ownership Last Name] is not null or p.[1st Ownership Question] is not null
drop table #temp
You need an extra field to get some order in that data with all the duplicates.
For example a primary key.
Then you can use a pivot with a row_number that uses that extra field in the order by.
Then concat the row_number with the name1, and Pivot on those.
For example :
create table #temp (id int identity(1,1), instanceid int, submissionid int, name1 varchar(20), value1 varchar(20));
insert into #temp(instanceid,submissionid,name1,value1) values
(5151,5532,'First','Mujda'),
(5151,5532,'Last','Zhublawar'),
(5151,5532,'Question_1','Y'),
(5151,5532,'First','Mujda1'),
(5151,5532,'Last','Zhublawar1'),
(5151,5532,'Question_1','Y'),
(5151,5532,'First','Mujda1'),
(5151,5532,'Last','Zhublawar1'),
(5151,5532,'Question_1','Y'),
(5151,5533,'First','Muthu'),
(5151,5533,'Last','Kumar'),
(5151,5533,'Question_1','Y'),
(5151,5534,'First','Suresh'),
(5151,5534,'Last','Kumar'),
(5151,5534,'Question_1','Y'),
(5151,5534,'First','Suresh1'),
(5151,5534,'Last','Kumar1'),
(5151,5534,'Question_1','Y');
SELECT
instanceid,
submissionid,
[First1] as [1st First], [Last1] as [1st Last], [Question_11] as [1st Question_1],
[First2] as [2nd First], [Last2] as [2nd Last], [Question_12] as [2nd Question_1],
[First3] as [3rd First], [Last3] as [3rd Last], [Question_13] as [3rd Question_1]
FROM (
select
instanceid,
submissionid,
concat(name1, row_number() over (partition by instanceid, submissionid, name1 order by id)) as name_rn, value1
from #temp
where name1 in ('First','Last','Question_1')
) t
PIVOT( MAX(value1)
FOR name_rn IN (
[First1], [Last1], [Question_11],
[First2], [Last2], [Question_12],
[First3], [Last3], [Question_13]
)
) AS Pvt;
To do it the dynamic way, here's some SQL to generate a #SQL variable.
declare #T table (name1 varchar(20));
insert into #T select name1 from #temp group by name1 order by name1;
declare #SQL nvarchar(max);
declare #Fields1 nvarchar(max);
declare #Fields2 nvarchar(max);
SELECT #Fields2 = STUFF((select ', ' + quotename(name1) from #T order by name1 FOR XML PATH('')),1,1,'');
SET #Fields2 = replace(#Fields2,']','1]')+','+char(13)+replace(#Fields2,']','2]')+','+char(13)+replace(#Fields2,']','3]');
SELECT #Fields1 = STUFF((select ',$' + quotename(name1+n)+' as '+quotename(nx+' '+name1) from (
select '1' as n, '1st' as nx, name1 from #T union all
select '2', '2nd' as nx, name1 from #T union all
select '3', '3rd' as nx, name1 from #T
) q order by n, name1 FOR XML PATH('')),1,1,'');
SET #Fields1 = replace(#Fields1,'$',char(13));
SET #SQL =
'SELECT
instanceid,
submissionid,'+#Fields1+'
FROM (
select
instanceid,
submissionid,
concat(name1, row_number() over (partition by instanceid, submissionid, name1 order by id)) as name_rn, value1
from #temp
) t
PIVOT( MAX(value1)
FOR name_rn IN ('+char(13)+#Fields2+')
) AS Pvt';
select #SQL;
--Get unique values of pivot column
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME(seq)
FROM (
select DISTINCT (name1) as seq
from #temp group by value1,name1,instanceid
) AS PivotExample
This are is your problem you are concatenating a row_number into the name1 value which would always be null. Your column list needs to be the DISTINCT values in name1 NOT what you want them to be in the end. If you want to rename columns you would alias them after the pivot or change the value in name1 prior to running the pivot.
So in the above code I removed the ROW_NUMBER() and added DISTINCT to the derived table.
Also note the test data you included has some instanceid & submissionid combinations that are missing certain fields like first name, or question. It looks like when copying and pasting you just didn't correct the correlations.

Convert dynamic text data rows into multiple columns

I'm trying to convert my result table which consist of multiple rows into multiple columns. below are my sample result before and after:
Before:
After:
Got a some idea from here but still no luck.
Update 1:
select #cols = STUFF((select ',' + QUOTENAME(institution) + ',' + QUOTENAME(intstatus)
From #temp
group by refno,frmstatus
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
i have no idea how to insert each column into the pivot query
set #query = 'select refno, frmstatus,' + #cols + '
from (
select refno, frmstatus, institution, intstatus from #temp
) x
pivot
(
???????
)
Please try the below query:
CREATE TABLE #temp(refno nvarchar(20), firmstatus nvarchar(20), institution nvarchar(20), intstatus nvarchar(20), ranking int)
DECLARE #qu NVARCHAR(MAX), #pcol NVARCHAR(MAX)
INSERT INTO #temp
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY refno ORDER BY institution ASC) AS ranking
FROM temp
SELECT #pcol=
STUFF((
SELECT
DISTINCT N', Institution'+ CAST (ranking AS NVARCHAR(25)) +', '+ N'Intstatus'+ CAST (ranking AS NVARCHAR(25))
FROM #temp
FOR XML PATH('')),1,1,'')
SET #qu=N'SELECT refno, firmstatus,'+ #pcol +
N' FROM
(
select refno,firmstatus,ColData,colheader+ CAST(ranking as varchar) as colnames from
(select * from #temp)s
UNPIVOT
(ColData for colheader in ([institution], [intstatus])) up
)S
PIVOT
(MAX(ColData) FOR colnames IN ('+#pcol +N')) AS piv'
EXEC sp_executesql #qu -- execute the dynamic sql
DROP TABLE #temp -- remove the temp table
The temp table in above script was created like below
--create table temp( refno nvarchar(20), firmstatus nvarchar(20), institution nvarchar(20), intstatus nvarchar(20))
--insert into temp values
--('AAA/1','Active','InstA','Ongoing'),
--('AAA/1','Active','InstB','Ongoing'),
--('AAA/1','Active','InstC','Ongoing'),
--('AAA/2','Active','InstA','Ongoing'),
--('AAA/2','Active','InstB','Ongoing')
Result received:
If repeated columns number is small and restricted, you can use simple solution:
WITH A AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY refno, fmstatus ORDER BY institution) n
FROM myTable
),
B AS (
SELECT refno, fmstatus,
CASE WHEN n=1 THEN institution END institution,
CASE WHEN n=1 THEN intstatus END intstatus,
CASE WHEN n=2 THEN institution END institution1,
CASE WHEN n=2 THEN intstatus END intstatus1,
CASE WHEN n=3 THEN institution END institution2,
CASE WHEN n=3 THEN intstatus END intstatus2
FROM A
)
SELECT refno, fmstatus,
MAX(institution) institution,
MAX(intstatus) intstatus,
MAX(institution1) institution1,
MAX(intstatus1) intstatus1,
MAX(institution2) institution2,
MAX(intstatus2) intstatus2
FROM B
GROUP BY refno, fmstatus
Otherwise use PIVOT

Dynamic SELECT statement, generate columns based on present and future values

Currently building a SELECT statement in SQL Server 2008 but would like to make this SELECT statement dynamic, so the columns can be defined based on values in a table. I heard about pivot table and cursors, but seems kind of hard to understand at my current level, here is the code;
DECLARE #date DATE = null
IF #date is null
set # date = GETDATE() as DATE
SELECT
Name,
value1,
value2,
value3,
value4
FROM ref_Table a
FULL OUTER JOIN (
SELECT
PK_ID ID,
sum(case when FK_ContainerType_ID = 1 then 1 else null) Box,
sum(case when FK_ContainerType_ID = 2 then 1 else null) Pallet,
sum(case when FK_ContainerType_ID = 3 then 1 else null) Bag,
sum(case when FK_ContainerType_ID = 4 then 1 else null) Drum
from
Packages
WHERE
#date between PackageStart AND PackageEnd
group by PK_ID ) b on a.Name = b.ID
where
Group = 0
The following works great for me , but PK_Type_ID and the name of the column(PackageNameX,..) are hard coded, I need to be dynamic and it can build itself based on present or futures values in the Package table.
Any help or guidance on the right direction would be greatly appreciated...,
As requested
ref_Table (PK_ID, Name)
1, John
2, Mary
3, Albert
4, Jane
Packages (PK_ID, FK_ref_Table_ID, FK_ContainerType_ID, PackageStartDate, PackageEndDate)
1 , 1, 4, 1JAN2014, 30JAN2014
2 , 2, 3, 1JAN2014, 30JAN2014
3 , 3, 2, 1JAN2014, 30JAN2014
4 , 4, 1, 1JAN2014, 30JAN2014
ContainerType (PK_ID, Type)
1, Box
2, Pallet
3, Bag
4, Drum
and the result should look like this;
Name Box Pallet Bag Drum
---------------------------------------
John 1
Mary 1
Albert 1
Jane 1
The following code like I said works great, the issue is the Container table is going to grow and I need to replicated the same report without hard coding the columns.
What you need to build is called a dynamic pivot. There are plenty of good references on Stack if you search out that term.
Here is a solution to your scenario:
IF OBJECT_ID('tempdb..##ref_Table') IS NOT NULL
DROP TABLE ##ref_Table
IF OBJECT_ID('tempdb..##Packages') IS NOT NULL
DROP TABLE ##Packages
IF OBJECT_ID('tempdb..##ContainerType') IS NOT NULL
DROP TABLE ##ContainerType
SET NOCOUNT ON
CREATE TABLE ##ref_Table (PK_ID INT, NAME NVARCHAR(50))
CREATE TABLE ##Packages (PK_ID INT, FK_ref_Table_ID INT, FK_ContainerType_ID INT, PackageStartDate DATE, PackageEndDate DATE)
CREATE TABLE ##ContainerType (PK_ID INT, [Type] NVARCHAR(50))
INSERT INTO ##ref_Table (PK_ID,NAME)
SELECT 1,'John' UNION
SELECT 2,'Mary' UNION
SELECT 3,'Albert' UNION
SELECT 4,'Jane'
INSERT INTO ##Packages (PK_ID, FK_ref_Table_ID, FK_ContainerType_ID, PackageStartDate, PackageEndDate)
SELECT 1,1,4,'2014-01-01','2014-01-30' UNION
SELECT 2,2,3,'2014-01-01','2014-01-30' UNION
SELECT 3,3,2,'2014-01-01','2014-01-30' UNION
SELECT 4,4,1,'2014-01-01','2014-01-30'
INSERT INTO ##ContainerType (PK_ID, [Type])
SELECT 1,'Box' UNION
SELECT 2,'Pallet' UNION
SELECT 3,'Bag' UNION
SELECT 4,'Drum'
DECLARE #DATE DATE, #PARAMDEF NVARCHAR(MAX), #COLS NVARCHAR(MAX), #SQL NVARCHAR(MAX)
SET #DATE = '2014-01-15'
SET #COLS = STUFF((SELECT DISTINCT ',' + QUOTENAME(T.[Type])
FROM ##ContainerType T
FOR XML PATH, TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET #SQL = 'SELECT [Name], ' + #COLS + '
FROM (SELECT [Name], [Type], 1 AS Value
FROM ##ref_Table R
JOIN ##Packages P ON R.PK_ID = P.FK_ref_Table_ID
JOIN ##ContainerType T ON P.FK_ContainerType_ID = T.PK_ID
WHERE #DATE BETWEEN P.PackageStartDate AND P.PackageEndDate) X
PIVOT (COUNT(Value) FOR [Type] IN (' + #COLS + ')) P
'
PRINT #COLS
PRINT #SQL
SET #PARAMDEF = '#DATE DATE'
EXEC SP_EXECUTESQL #SQL, #PARAMDEF, #DATE=#DATE
Output:
Name Bag Box Drum Pallet
Albert 0 0 0 1
Jane 0 1 0 0
John 0 0 1 0
Mary 1 0 0 0
Static Query:
SELECT [Name],[Box],[Pallet],[Bag],[Drum] FROM
(
SELECT *
FROM
(
SELECT rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
) AS SourceTable
PIVOT
(
COUNT(PKID )
FOR [Type]
IN ( [Box],[Pallet],[Bag],[Drum])
) AS PivotTable
) AS Main
ORDER BY RFID
Dynamic Query:
DECLARE #columnList nvarchar (MAX)
DECLARE #pivotsql nvarchar (MAX)
SELECT #columnList = STUFF(
(
SELECT ',' + '[' + [Type] + ']'
FROM ContanerType
FOR XML PATH( '')
)
,1, 1,'' )
SET #pivotsql =
N'SELECT [Name],' + #columnList + ' FROM
(
SELECT *
FROM
(
SELECT rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
) AS SourceTable
PIVOT
(
COUNT(PKID )
FOR [Type]
IN ( ' + #columnList + ')
) AS PivotTable
) AS Main
ORDER BY RFID;'
EXEC sp_executesql #pivotsql
Following my tutorial below will help you to understand the PIVOT functionality:
We write sql queries in order to get different result sets like full, partial, calculated, grouped, sorted etc from the database tables. However sometimes we have requirements that we have to rotate our tables. Sounds confusing?
Let's keep it simple and consider the following two screen grabs.
SQL Table:
Expected Results:
Wow, that's look like a lot of work! That is a combination of tricky sql, temporary tables, loops, aggregation......, blah blah blah
Don't worry let's keep it simple, stupid(KISS).
MS SQL Server 2005 and above has a function called PIVOT. It s very simple to use and powerful. With the help of this function we will be able to rotate sql tables and result sets.
Simple steps to make it happen:
Identify all the columns those will be part of the desired result set.
Find the column on which we will apply aggregation(sum,ave,max,min etc)
Identify the column which values will be the column header.
Specify the column values mentioned in step3 with comma separated and surrounded by square brackets.
So, if we now follow above four steps and extract information from the above sales table, it will be as below:
Year, Month, SalesAmount
SalesAmount
Month
[Jan],[Feb] ,[Mar] .... etc
We are nearly there if all the above steps made sense to you so far.
Now we have all the information we need. All we have to do now is to fill the below template with required information.
Template:
Our SQL query should look like below:
SELECT *
FROM
(
SELECT SalesYear, SalesMonth,Amount
FROM Sales
) AS SourceTable
PIVOT
(
SUM(Amount )
FOR SalesMonth
IN ( [Jan],[Feb] ,[Mar],
[Apr],[May],[Jun] ,[Jul],
[Aug],[Sep] ,[Oct],[Nov] ,[Dec])
) AS PivotTable;
In the above query we have hard coded the column names. Well it's not fun when you have to specify a number of columns.
However, there is a work arround as follows:
DECLARE #columnList nvarchar (MAX)
DECLARE #pivotsql nvarchar (MAX)
SELECT #columnList = STUFF(
(
SELECT ',' + '[' + SalesMonth + ']'
FROM Sales
GROUP BY SalesMonth
FOR XML PATH( '')
)
,1, 1,'' )
SET #pivotsql =
N'SELECT *
FROM
(
SELECT SalesYear, SalesMonth,Amount
FROM Sales
) AS SourceTable
PIVOT
(
SUM(Amount )
FOR SalesMonth
IN ( ' + #columnList +' )
) AS PivotTable;'
EXEC sp_executesql #pivotsql
Hopefully this tutorial will be a help to someone somewhere.
Enjoy coding.

showing rows of table as columns based on some ID

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