Columns to rows and rows to column conversion without pivot/unpivot - sql

All I need is convert Column(A1/A2) into rows and rows(1 into Jan) into columns.
Input:
Here A1/A2 belongs to say A and they are calculated as A1/A2 for each month.
Month A1 A2 B1 B2 C1 C2
1 120 60 40 80 120 120
2 50 50 40 20 60 30
3 50 25 40 10 90 30
I need below o/p without using pivot and unpivot
O/P:
X Jan(1 is denoting Jan) Feb Mar
A 120/60(calculation:A1/A2) 40/80 120/120
B 50/50 40/20 60/30
C 50/25 40/10 90/30
I tried but my query is too long as I am using case and Union All three times each For A1 A2,B1 B2,C1 C2 etc.

Using cross apply(values ...) and conditional aggregation:
select
v.X
, Jan = max(case when t.month=1 then v.Value end)
, Feb = max(case when t.month=2 then v.Value end)
, Mar = max(case when t.month=3 then v.Value end)
from t
cross apply(values
('A',convert(varchar(3),A1)+'/'+convert(varchar(3),A2))
,('B',convert(varchar(3),B1)+'/'+convert(varchar(3),B2))
,('C',convert(varchar(3),C1)+'/'+convert(varchar(3),C2))
) v (X,Value)
group by v.X
rextester demo: http://rextester.com/XICI74484
returns:
+---+---------+-------+-------+
| X | Jan | Feb | Mar |
+---+---------+-------+-------+
| A | 120/60 | 50/50 | 50/25 |
| B | 40/80 | 40/20 | 40/10 |
| C | 120/120 | 60/30 | 90/30 |
+---+---------+-------+-------+
For the evaluation of the expressions:
select
v.X
, Jan = max(case when t.month=1 then v.Value end)
, Feb = max(case when t.month=2 then v.Value end)
, Mar = max(case when t.month=3 then v.Value end)
from t
cross apply(values
('A',(A1*1.0)/A2)
,('B',(B1*1.0)/B2)
,('C',(C1*1.0)/C2)
) v (X,Value)
group by v.X
returns:
+---+------+------+------+
| X | Jan | Feb | Mar |
+---+------+------+------+
| A | 2.00 | 1.00 | 2.00 |
| B | 0.50 | 2.00 | 4.00 |
| C | 1.00 | 2.00 | 3.00 |
+---+------+------+------+

You can use XML. This snippet may be more than you want but it shows how
--------------------------------------------------
-----------------Begin TRANSPOSE-----------------
--------------------------------------------------
DECLARE #xml XML
,#RowCount BIGINT
DECLARE #sSQl NVARCHAR(MAX)= 'SELECT (SELECT DISTINCT ColumnName FROM #TempTable WHERE CellId=Cell.CellId) as ColumnName,'
---------------------------------------------------
--Set up #table Here or outside the code... but #TABLE WILL BE DROPPED AT FINISH
---------------------------------------------------
--#############################################################################
-- the temp table #Table will contain what you want to Transpose
--#############################################################################
--SELECT * INTO #Table FROM Widgets W WHERE WidgetId IN (1096,803)
---------------------------------------------------
---------------- End #Table Setup ---------------
---------------------------------------------------
SET #xml = (SELECT *
,ROW_NUMBER() OVER (ORDER BY (SELECT 1
)) Rn
FROM #Table Row
FOR
XML AUTO
,ROOT('Root')
,ELEMENTS XSINIL
);
WITH RC AS
(SELECT COUNT(Row.value('.', 'nvarchar(MAX)')) [RowCount]
FROM #xml.nodes('Root/Row') AS WTable(Row))
,c AS(
SELECT b.value('local-name(.)','nvarchar(max)') ColumnName,
b.value('.[not(#xsi:nil = "true")]','nvarchar(max)') Value,
b.value('../Rn[1]','nvarchar(max)') Rn,
ROW_NUMBER() OVER (PARTITION BY b.value('../Rn[1]','nvarchar(max)') ORDER BY (SELECT 1)) Cell
FROM
#xml.nodes('//Root/Row/*[local-name(.)!="Rn"]') a(b)
),Cols AS (
SELECT DISTINCT c.ColumnName,
c.Cell
FROM c
)
INSERT INTO #TempTable (CellId,RowID,Value,ColumnName)
SELECT Cell,Rn,Value,REPLACE(c.ColumnName,'_x0023_','#')
FROM c
SELECT #sSQL = #sSQl + '(SELECT T2.Value FROM #Temptable T2 WHERE T2.CellId=Cell.CellID AND T2.Rowid=' + CAST(T.RowId AS NVARCHAR) + ') AS __________________Value____________________'
+ CAST(T.RowID AS NVARCHAR) + ','
FROM (SELECT DISTINCT
RowId
FROM #TempTable
) T
SET #sSQl = LEFT(#sSQL, LEN(#sSQL) - 1) + ' FROM (SELECT DISTINCT CellId FROM #TempTable) Cell order by columnname'
EXECUTE sp_Executesql #sSQl
--here you will have your output
-- PRINT #sSQl
DROP TABLE #Table
DROP TABLE #TempTable
--------------------------------------------------
-----------------END TRANSPOSE-------------------
--------------------------------------------------

Related

How to combine multiple SQL rows into columns dynamically

I have a table with
+-------+-------+-----------------+
| P1_ID | P2_ID | Relationship_ID |
+-------+-------+-----------------+
| 1 | 21 | 3 |
| 1 | 32 | 3 |
| 2 | 45 | 2 |
| 2 | 65 | 1 |
| 3 | 98 | 3 |
| 3 | 94 | 4 |
+-------+-------+-----------------+
I want the final table to look like:
+-------+--------+--------+------+------+
| P1_ID | P2_ID1 | P2_ID2 | RID1 | RID2 |
+-------+--------+--------+------+------+
| 1 | 21 | 32 | 3 | 3 |
| 2 | 45 | 65 | 2 | 1 |
| 3 | 98 | 94 | 3 | 4 |
+-------+--------+--------+------+------+
I am not sure which direction to go with this. I am trying to use a pivot but I can not seem to make it work. Maybe I am doing it wrong.
You can use conditional aggregation for this. This isn't exactly what you stated for output because the ordering of your data is a little funky. But this should point you in the right direction.
declare #Something table
(
P1_ID int
, P2_ID int
, Realationship_ID int
)
insert #Something values
(1,21,3)
, (1,32,3)
, (2,45,2)
, (2,65,1)
, (3,98,3)
, (3,94,4)
select P1_ID
, P2_ID1 = MAX(Case when RowNum = 1 then P2_ID end)
, P2_ID2 = max(case when RowNum = 2 then P2_ID end)
, RID1 = MAX(Case when RowNum = 1 then Realationship_ID end)
, RID2 = max(case when RowNum = 2 then Realationship_ID end)
from
(
select *
, RowNum = ROW_NUMBER() over(partition by s.P1_ID order by Realationship_ID)
from #Something s
) x
group by x.P1_ID
--EDIT--
Here is a fully dynamic solution for this. I switched to using a temp table because a table variable would be out of scope for dynamic sql. Obviously in your situation you would be using a persistent table. This will order the output by P1_ID and the columns within each row by Realationship_ID.
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
P1_ID int
, P2_ID int
, Realationship_ID int
)
insert #Something values
(1,21,3)
, (1,32,3)
, (2,45,2)
, (2,65,1)
, (3,98,3)
, (3,94,4)
;
declare #DynamicPortion nvarchar(max) = '';
declare #FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by P1_ID order by P1_ID';
declare #StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *
, RowNum = ROW_NUMBER() over(partition by s.P1_ID order by Realationship_ID)
from #Something s
)
select P1_ID';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a cross join E1 b), --10E+2 or 100 rows
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E2
)
select #DynamicPortion = #DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then P2_ID end) as P2_ID' + CAST(N as varchar(6)) + CHAR(10) +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Realationship_ID end) as RID' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from #Something
group by P1_ID
order by COUNT(*) desc
)
declare #SqlToExecute nvarchar(max) = #StaticPortion + #DynamicPortion + #FinalStaticPortion;
exec sp_executesql #SqlToExecute

How to join same records in sql server

I have data like this :
| ID | NAME | PRICE
| 01 | TEST | 5000
| 01 | TEST | 10000
| 02 | EAST | 4500
| 03 | AEST | 5000
| 03 | AEST | 5000
I want to join that same records so the final result is like this :
| ID | NAME | PRICE1 | PRICE2
| 01 | TEST | 5000 | 10000
| 02 | EAST | 4500 | 0
| 03 | AEST | 5000 | 5000
SQL tables represent unordered sets. Given the information you have provided, there is no way to determine the price1 and price2 as you have specified. So, you might as well use MIN() and MAX():
select id, name, min(price) as price1, max(price) as price2
from t
group by id, name;
If you did have a column that specified the ordering, then you could use pivot or conditional aggregation:
select id, name,
max(case when seqnum = 1 then price end) as price1,
max(case when seqnum = 2 then price end) as price2
from (select t.*,
row_number() over (partition by id order by ??) as seqnum
from t
) t
group by id, name;
The ?? is for the column that specifies the ordering.
IF OBJECT_ID('Tempdb..#Temp') IS NOT NULL
Drop table #Temp
;With cte(ID,NAME,PRICE)
AS
(
SELECT 01 , 'TEST' , 5000 UNION ALL
SELECT 01 , 'TEST' , 10000 UNION ALL
SELECT 02 , 'EAST' , 4500 UNION ALL
SELECT 03 , 'AEST' , 5000 UNION ALL
SELECT 03 , 'AEST' , 5000
)
SELECT *, 'Price' + CAST(ROW_NUMBER()Over(PArtition by NAME Order by NAME) AS Varchar(5)) AS PriceCol INTO #Temp FROM cte
DECLARE #Coulmn nvarchar(max),
#Coulmn2 nvarchar(max),
#Sql nvarchar(max)
SELECT #Coulmn=STUFF((SELECT DISTINCT ', '+ '['+ PriceCol +']' From #Temp
FOR XML PATH ('')),1,1,'')
--SELECT #Coulmn
SELECT #Coulmn2=STUFF((SELECT DISTINCT ', '+ 'ISNULL(' + PriceCol + ',''0'')' +' AS ['+PriceCol +']' From #Temp
FOR XML PATH ('')),1,1,'')
--SELECT #Coulmn2
SET #Sql=' SELECT ID,NAME, '+#Coulmn2+ ' From
(
SELECT * From #Temp
)As Src
PIVOT
(
MAX(PRICE) FOR PriceCol IN ('+ #Coulmn +')
)Pvt
Order By Pvt.ID
'
Print #Sql
Exec(#Sql)

SQL Server Rows to Multi-Columns

I have the following table and data:
CREATE TABLE SourceTbl ([Code] varchar(3), [Total] decimal, [Date] datetime );
INSERT INTO SourceTbl ([Code], [Total], [Date])
VALUES ('AA', 100, '2012-12-01'), ('AA', 200, '2013-02-01'), ('BB', 50, '2012-01-01');
A simple select will return
Code | Total | Date
'AA' | 100 | 2012-12-01
'AA' | 200 | 2013-02-01
'BB' | 50 | 2012-01-01
but what I need is the following
Code | Total | Date | Total | Date
'AA | 200 | 2013-02-01 | 100 | 2012-12-01
'BB | 50 | 2012-01-01 | null | null
I have been trying to do this using a PIVOT operator but without success (based on the question SQL Server Pivot multiple columns based on one column).
Using that example, all I get are two rows with null values.
The Total/Date columns can be repeated 13 times and they must be ordered by Date DESC.
SQL Fiddle: http://sqlfiddle.com/#!3/f37a1/2
Any help is appreciated!
Thanks!
If you need just two columns:
with cte as (
select *, row_number() over(partition by Code order by Date) as rn
from SourceTbl
)
select
code,
max(case when rn = 1 then Total end) as Total1,
max(case when rn = 1 then Date end) as Date1,
max(case when rn = 2 then Total end) as Total2,
max(case when rn = 2 then Date end) as Date2
from cte
group by code
=> sql fiddle demo
dynamic solution:
declare #stmt nvarchar(max)
;with cte as (
select distinct
cast(row_number() over(partition by Code order by Date) as nvarchar(max)) as rn
from SourceTbl
)
select #stmt = isnull(#stmt + ', ', '') +
'max(case when rn = ' + rn + ' then Total end) as Total' + rn + ',' +
'max(case when rn = ' + rn + ' then Date end) as Date' + rn
from cte
order by rn
select #stmt = '
with cte as (
select *, row_number() over(partition by Code order by Date) as rn
from SourceTbl
)
select
code, ' + #stmt + ' from cte group by code'
exec sp_executesql
#stmt = #stmt
=> sql fiddle demo
Are you trying to dynamically create columns in your result set?
If you had a third record of 'AA' with a total of 300 and the date of 03/01/2013 would you that mean you would want something like this displayed?
Code | Total | Date | Total | Date | Total | Date
AA | 200 | 2013-02-01 | 100 | 2012-12-01| 300 | 03-01-13
BB | 50 | 2012-01-01 | null | null | null | null

SQL Server : dynamic pivot over 5 columns

I'm having a very tough time trying to figure out how to do a dynamic pivot in SQL Server 2008 with multiple columns.
My sample table is as follows:
ID YEAR TYPE TOTAL VOLUME
DD1 2008 A 1000 10
DD1 2008 B 2000 20
DD1 2008 C 3000 30
DD1 2009 A 4000 40
DD1 2009 B 5000 50
DD1 2009 C 6000 60
DD2 2008 A 7000 70
DD2 2008 B 8000 80
DD2 2008 C 9000 90
DD2 2009 A 10000 100
DD2 2009 B 11000 110
DD2 2009 C 12000 120
and I'm trying the pivot it as follows:
ID 2008_A_TOTAL 2008_A_VOLUME 2008_B_TOTAL 2008_B_VOLUME 2008_C_TOTAL 2008_C_VOLUME 2009_A_TOTAL 2009_A_VOLUME 2009_B_TOTAL 2009_B_VOLUME 2009_C_TOTAL 2009_C_VOLUME
DD1 1000 10 2000 20 3000 30 4000 40 5000 50 6000 60
DD2 7000 70 8000 80 9000 90 10000 100 11000 110 12000 120
My SQL Server 2008 query is as follows to create the table:
CREATE TABLE ATM_TRANSACTIONS
(
ID varchar(5),
T_YEAR varchar(4),
T_TYPE varchar(3),
TOTAL int,
VOLUME int
);
INSERT INTO ATM_TRANSACTIONS
(ID,T_YEAR,T_TYPE,TOTAL,VOLUME)
VALUES
('DD1','2008','A',1000,10),
('DD1','2008','B',2000,20),
('DD1','2008','C',3000,30),
('DD1','2009','A',4000,40),
('DD1','2009','B',5000,50),
('DD1','2009','C',6000,60),
('DD2','2008','A',7000,70),
('DD2','2008','B',8000,80),
('DD2','2008','C',9000,90),
('DD2','2009','A',10000,100),
('DD2','2009','B',11000,110),
('DD2','2009','C',1200,120);
The T_Year column may change in the future but the T_TYPE column is generally know, so I'm not sure if I can use a combination of the PIVOT function in SQL Server with dynamic code?
I tried following the example here:
http://social.technet.microsoft.com/wiki/contents/articles/17510.t-sql-dynamic-pivot-on-multiple-columns.aspx
but I ended up with with weird results.
In order to get the result, you will need to look at unpivoting the data in the Total and Volume columns first before applying the PIVOT function to get the final result. My suggestion would be to first write a hard-coded version of the query then convert it to dynamic SQL.
The UNPIVOT process converts these multiple columns into rows. There are a few ways to UNPIVOT, you can use the UNPIVOT function or you can use CROSS APPLY. The code to unpivot the data will be similar to:
select id,
col = cast(t_year as varchar(4))+'_'+t_type+'_'+col,
value
from ATM_TRANSACTIONS t
cross apply
(
select 'total', total union all
select 'volume', volume
) c (col, value);
This gives you data in the format:
+-----+---------------+-------+
| id | col | value |
+-----+---------------+-------+
| DD1 | 2008_A_total | 1000 |
| DD1 | 2008_A_volume | 10 |
| DD1 | 2008_B_total | 2000 |
| DD1 | 2008_B_volume | 20 |
| DD1 | 2008_C_total | 3000 |
| DD1 | 2008_C_volume | 30 |
+-----+---------------+-------+
Then you can apply the PIVOT function:
select ID,
[2008_A_total], [2008_A_volume], [2008_B_total], [2008_B_volume],
[2008_C_total], [2008_C_volume], [2009_A_total], [2009_A_volume]
from
(
select id,
col = cast(t_year as varchar(4))+'_'+t_type+'_'+col,
value
from ATM_TRANSACTIONS t
cross apply
(
select 'total', total union all
select 'volume', volume
) c (col, value)
) d
pivot
(
max(value)
for col in ([2008_A_total], [2008_A_volume], [2008_B_total], [2008_B_volume],
[2008_C_total], [2008_C_volume], [2009_A_total], [2009_A_volume])
) piv;
Now that you have the correct logic, you can convert this to dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(cast(t_year as varchar(4))+'_'+t_type+'_'+col)
from ATM_TRANSACTIONS t
cross apply
(
select 'total', 1 union all
select 'volume', 2
) c (col, so)
group by col, so, T_TYPE, T_YEAR
order by T_YEAR, T_TYPE, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT id,' + #cols + '
from
(
select id,
col = cast(t_year as varchar(4))+''_''+t_type+''_''+col,
value
from ATM_TRANSACTIONS t
cross apply
(
select ''total'', total union all
select ''volume'', volume
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute sp_executesql #query;
This will give you a result:
+-----+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+
| id | 2008_A_total | 2008_A_volume | 2008_B_total | 2008_B_volume | 2008_C_total | 2008_C_volume | 2009_A_total | 2009_A_volume | 2009_B_total | 2009_B_volume | 2009_C_total | 2009_C_volume |
+-----+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+
| DD1 | 1000 | 10 | 2000 | 20 | 3000 | 30 | 4000 | 40 | 5000 | 50 | 6000 | 60 |
| DD2 | 7000 | 70 | 8000 | 80 | 9000 | 90 | 10000 | 100 | 11000 | 110 | 1200 | 120 |
+-----+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+--------------+---------------+
declare #stmt nvarchar(max)
select #stmt = isnull(#stmt + ', ', '') +
'sum(case when T_YEAR = ''' + T.T_YEAR + ''' and T_TYPE = ''' + T.T_TYPE + ''' then TOTAL else 0 end) as ' + quotename(T.T_YEAR + '_' + T.T_TYPE + '_TOTAL') + ',' +
'sum(case when T_YEAR = ''' + T.T_YEAR + ''' and T_TYPE = ''' + T.T_TYPE + ''' then VOLUME else 0 end) as ' + quotename(T.T_YEAR + '_' + T.T_TYPE + '_VOLUME')
from (select distinct T_YEAR, T_TYPE from ATM_TRANSACTIONS) as T
order by T_YEAR, T_TYPE
select #stmt = '
select
ID, ' + #stmt + ' from ATM_TRANSACTIONS group by ID'
exec sp_executesql
#stmt = #stmt
unfortunately, sqlfiddle.com is not working at the moment, so I cannot create an example for you.
The query created by dynamic SQL would be:
select
ID,
sum(case when T_YEAR = '2008' and T_TYPE = 'A' then TOTAL else 0 end) as 2008_A_TOTAL,
sum(case when T_YEAR = '2008' and T_TYPE = 'A' then VOLUME else 0 end) as 2008_A_VOLUME,
...
from ATM_TRANSACTIONS
group by ID
Please try:
DECLARE #pivv NVARCHAR(MAX),#Query NVARCHAR(MAX)
SELECT #pivv=COALESCE(#pivv+',','')+ QUOTENAME(T_YEAR+'_'+T_TYPE+'_TOTAL')+','+QUOTENAME(T_YEAR+'_'+T_TYPE+'_VOLUME') from ATM_TRANSACTIONS GROUP BY T_YEAR, T_TYPE
IF ISNULL(#pivv, '')<>''
SET #Query='SELECT * FROM(
SELECT ID, T_YEAR+''_''+T_TYPE+''_TOTAL'' TYP, TOTAL VAL from ATM_TRANSACTIONS UNION
SELECT ID, T_YEAR+''_''+T_TYPE+''_VOLUME'' TYP, VOLUME VAL from ATM_TRANSACTIONS
)x pivot (SUM(VAL) for TYP in ('+#pivv+')) as xx'
IF ISNULL(#Query, '')<>''
EXEC (#Query)

Pivot table to turn rows into columns

I currently run the query
SELECT [PriceAttributeID]
,[PriceID]
,[AttributeID]
,[PriceAttributeComparator]
,[PriceAttributeMin]
,[PriceAttributeMax]
FROM [PriceAttribute]
Which gives the output
1 2 1 1 S NULL
2 3 1 1 M NULL
3 4 1 1 L NULL
4 5 1 1 L NULL
5 5 2 1 Black NULL
I would like to get the output (where _Comp, _Min and _Max relate to PriceAttributeComparator, PriceAttributeMin and PriceAttributeMax)
PriceID 1_Comp 1_Min 1_Max 2_Comp 2_Min 2_Max
2 1 S NULL NULL NULL NULL
3 1 M NULL NULL NULL NULL
4 1 L NULL NULL NULL NULL
5 1 L NULL 1 Black NULL
The same query would also be expected to have 1_ and 2_ prefixes as 4_, 5_, 19_ and 32_ or any other indeterminate number of ID's based on what is in the table at the time.
I have attempted a PIVOT table, but i am new to them and haven't the first clue on how to create what it is i am looking to do.
Part of the problem you are probably having with the PIVOT function is due to the fact you have multiple columns that you want to apply the function to. If you want to use the PIVOT function, then I would suggest first unpivoting the columns PriceAttributeComparator, PriceAttributeMin and PriceAttributeMax. When you unpivot the data you will no longer have multiple columns, you will have multiple rows, then you can apply the pivot to all of the appropriate values.
You did not specify what version of SQL Server you are using but you can use CROSS APPLY with a UNION ALL to unpivot the columns:
select priceid,
col = cast(attributeid as varchar(10))+'_'+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select 'comp', comp union all
select 'min', [min] union all
select 'max', [max]
) c (col, value)
See Demo. This process will convert your data into the following format:
| PRICEID | COL | VALUE |
-----------------------------
| 2 | 1_comp | 1 |
| 2 | 1_min | S |
| 2 | 1_max | (null) |
| 3 | 1_comp | 1 |
| 3 | 1_min | M |
| 3 | 1_max | (null) |
Once the data is in multiple rows, then you can apply the PIVOT function to the values in col:
select priceid,
[1_comp], [1_min], [1_max], [2_comp], [2_min], [2_max]
from
(
select priceid,
col = cast(attributeid as varchar(10))+'_'+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select 'comp', comp union all
select 'min', [min] union all
select 'max', [max]
) c (col, value)
) src
pivot
(
max(value)
for col in ([1_comp], [1_min], [1_max], [2_comp], [2_min], [2_max])
) piv;
See SQL Fiddle with Demo.
The above versions work great if you have a known number of values but if the values are unknown, then you will need to use dynamic SQL to get the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(cast(attributeid as varchar(10))+'_'+ col)
from
(
select distinct attributeid
from priceattribute
) d
cross apply
(
select 'comp', 1 union all
select 'min', 2 union all
select 'max', 3
) c (col, so)
group by attributeid, col, so
order by attributeid, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT priceid, ' + #cols + '
from
(
select priceid,
col = cast(attributeid as varchar(10))+''_''+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select ''comp'', comp union all
select ''min'', [min] union all
select ''max'', [max]
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo. These solutions will give a result:
| PRICEID | 1_COMP | 1_MIN | 1_MAX | 2_COMP | 2_MIN | 2_MAX |
----------------------------------------------------------------
| 2 | 1 | S | (null) | (null) | (null) | (null) |
| 3 | 1 | M | (null) | (null) | (null) | (null) |
| 4 | 1 | L | (null) | (null) | (null) | (null) |
| 5 | 1 | L | (null) | 1 | Black | (null) |
It might be simplest to do this using conditional aggregation rather than pivot:
SELECT PriceID,
max(case when AttributeID = 1 then PriceAttributeComparator end) as comp_1,
max(case when AttributeID = 1 then PriceAttributeMin end) as min_1,
max(case when AttributeID = 1 then PriceAttributeMax end) as max_1,
max(case when AttributeID = 2 then PriceAttributeComparator end) as comp_2,
max(case when AttributeID = 2 then PriceAttributeMin end) as min_2,
max(case when AttributeID = 2 then PriceAttributeMax end) as max_2
FROM PriceAttribute pa
group by PriceId;