I have some data that I want to pivot.
---------------------------------------------
| date | price | col_1 | col_2 |
---------------------------------------------
| 2017-12-10 | 26 | fruit | apple |
| 2017-12-10 | 346 | Vege | carrot |
| 2017-12-11 | 644 | Sweet | cake |
| 2017-12-11 | 35435 | fruit | banana |
| 2017-12-12 | 453455 | veggie| beans |
---------------------------------------------
col_1 and col_2 are combinations of categories
So basically the output should be 1 row per unique date, and the rest of the columns should be relevant combinations of col_1 and col2 separated by a hyphen. The table will be populated by the total price of the combination of col_1 col_2 item per date. the diagram below might be useful:
-------------------------------------------------------------------
| date | fruit - apple| fruit - banana| val n-SubVal n |
-------------------------------------------------------------------
| 2017-12-10 | NULL | 56 | and so on
| 2017-12-11 | 100 | NULL |
| 2017-12-12 | NULL | 900 |
| 2017-12-13 | 45 | NULL |
| 2017-12-14 | NULL | NULL |
--------------------------------------------------------------------
after about 4 hours talking to a friend and research we have come up with this script below. It executes but nothing gets returned except a very odd error.
Incorrect syntax near '*some value in either col_1 or col_2*'.
the error is supposedly happening either at the first or second declare statement (whichever line MSSQL randomly chooses as its never the same line #).
Any help in getting the above output will be appreciated.
Thank you very much.
declare #dynamicpivotquery as NVARCHAR(MAX)
declare #columnname as NVARCHAR(MAX)
select #columnname = COALESCE(#columnname + ', ','') + quotename(col_1) + quotename(col_1)
from (select distinct col_1, col_2 from *tablename*) as d
set #dynamicpivotquery =
N'select distinct date, ' + #columnname + ' from *tablename*
PIVOT (sum(price) for d in (' + #columnname + ')) as pivot12'
EXEC sp_executesql #dynamicpivotquery
Some remarks on your query:
The sample data has fieldnames date, price, col_1 and col_2 while your query uses fieldnames of sold_date, sold_price, cat_1 and cat_2.
You could have had a look at the result in the variable #dynamicpivotquery to see what's wrong: [fruit][apple] is not a valid fieldname. It should have been [fruit - apple] instead.
The PIVOT query did not know the field d with the concatenated category names.
The distinct in the dynamic query isn't needed. You have to make sure that only the required fields (sold_date, sold_price and d) are contained in the source for the PICOT command, because otherwise query will also be grouped by all additional fields, which will result in unwanted rows.
Your code could work like this:
DECLARE #dynamicpivotquery nvarchar(MAX)
DECLARE #columnnames nvarchar(MAX)
SELECT #columnnames =
ISNULL(#columnnames + ', ', '') + QUOTENAME(ISNULL(cat_1, '') + ' - ' + ISNULL(cat_2, ''))
FROM (SELECT DISTINCT cat_1, cat_2 FROM tablename) AS d
SET #dynamicpivotquery =
N'SELECT sold_date, ' + #columnnames + N'
FROM
(SELECT sold_date, sold_price,
ISNULL(cat_1, '''') + '' - '' + ISNULL(cat_2, '''') AS d
FROM tablename
) AS src
PIVOT (SUM(sold_price) FOR d IN (' + #columnnames + ')) AS pivot12'
EXEC sp_executesql #dynamicpivotquery
You can try the following query :
declare #dynamicpivotquery as NVARCHAR(MAX)
declare #columnname as NVARCHAR(MAX)
select #columnname = COALESCE(#columnname + ', ','') + QuoteName(cat)
from (select distinct cat_1+'-'+cat_2 as cat from #YourTable) as d
SET #dynamicpivotquery =
N';WITH p AS (
SELECT sold_date, [cat_1] +''-'' +[cat_2] AS CATCOL, SUM(sold_price) AS sold_price
FROM #YourTable
GROUP BY sold_date, [cat_1] + ''-'' + [cat_2]
)
SELECT sold_date, ' + #columnname + '
FROM p
PIVOT (SUM([sold_price]) FOR CATCOL IN (' + #columnname + ')) AS pivotcat12'
EXEC sp_executesql #dynamicpivotquery
Sample data :
sold_date sold_price cat_1 cat_2 cat_12
----------------------------------------------------
2017-12-10 26,00 fruit apple fruit-apple
2017-12-10 346,00 vege carrot vege-carrot
2017-12-11 644,00 sweet cake sweet-cake
2017-12-11 35435,00 fruit banana fruit-banana
2017-12-12 453455,00 veggie beans veggie-beans
2017-12-12 100,00 other fruits other-fruits
2017-12-12 100,00 other fruits other-fruits
2017-12-12 100,00 other fruits other-fruits
Dynamic query string :
;WITH p AS (
SELECT sold_date, [cat_1] +'-' +[cat_2] AS CATCOL, SUM(sold_price) AS sold_price
FROM #YourTable
GROUP BY sold_date, [cat_1] + '-' + [cat_2]
)
SELECT sold_date, [fruit-apple], [fruit-banana], [other-fruits], [sweet-cake], [vege-carrot], [veggie-beans]
FROM p
PIVOT (
SUM([sold_price])
FOR CATCOL IN ([fruit-apple], [fruit-banana], [other-fruits], [sweet-cake], [vege-carrot], [veggie-beans])) AS pivotcat12
Result :
sold_date fruit-apple fruit-banana other-fruits sweet-cake vege-carrot veggie-beans
--------------------------------------------------------------------------------------------
2017-12-10 26,00 NULL NULL NULL 346,00 NULL
2017-12-11 NULL 35435,00 NULL 644,00 NULL NULL
2017-12-12 NULL NULL 300,00 NULL NULL 453455,00
Pivot The data Twice. Just apply the same logic dynamically so that it appears for all combinations of col_1 and col_2.
select * from
( select [DATE], [col_1] ,[col_2],[price]
from *tablename*
) TableName
pivot
(sum(price)
for col_1 in (fruit)
) as FirstPivot
pivot
(sum(fruit)
for col_2 in (apple,banana)
) as SecondPivot
Related
I have a key value pair set of rows to associate to a unique identifier (ApplicationId).
The data would look something like this:
| ApplicationId | Key | Value | Date |
| 123 | A | abc | 2020-3-1 14:00:01.000 |
| 123 | B | abd | 2020-3-1 14:00:02.000 |
| 123 | C | abe | 2020-3-1 14:00:03.000 |
| 124 | A | abf | 2020-3-1 14:01:00.000 |
| 124 | D | abg | 2020-3-1 14:01:01.000 |
The end result i'm looking for would be this:
| ApplicationId | A | A_Date | B | B_Date | C | C_Date | D | D_Date |
| 123 | abc | 2020-3-1 14:00:01.000 | abd | 2020-3-1 14:00:02.000 | abe | 2020-3-1 14:00:03.000 | NULL | NULL |
| 124 | abf | 2020-3-1 14:01:00.000 | NULL | NULL | NULL | NULL | abg | 2020-3-1 14:01:01.000 |
The Keys A,B,C,D are unknown so hard coding the column names isn't possible.
Here is something that works with one PIVOT
IF OBJECT_ID('tempdb.dbo.#_BLAH') IS NOT NULL DROP TABLE #_BLAH
SELECT et.[ApplicationId] et.[Key], et.[Value], et.[Date]
INTO #_BLAH
FROM ExampleTbl et
WHERE et.[Date] > DATEADD(dd, -1, GetDate())
DECLARE #_cols AS NVARCHAR(MAX)
DECLARE #_sql AS NVARCHAR(MAX)
SELECT
#_cols += QUOTENAME([Key]) + ','
FROM
#_BLAH
GROUP BY
[Key];
SET #_cols = STUFF((SELECT ',' + QUOTENAME(T.[Key])
FROM #_BLAH AS T
GROUP BY T.[Key]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #_sql = 'SELECT [ApplicationId], ' + #_cols + '
FROM ( SELECT * FROM #_BLAH) AS SRC
PIVOT ( MAX([Value]) FOR [Key] IN (' + #_cols + ') ) AS p';
EXEC(#_sql)
I've so far been unable to find an example or an article attempting to make a second dynamic column and adding in the value that relates the specific Key in my example.
My SQL above will accomplish creating the row i want except for the #_Date column i need.
Try this:
DROP TABLE IF EXISTS #DataSource;
DROP TABLE IF EXISTS #DataSourcePrepared;
CREATE TABLE #DataSource
(
[ApplicationId] INT
,[Key] CHAR(1)
,[Value] VARCHAR(12)
,[Date] DATETIME2(0)
);
INSERT INTO #DataSource ([ApplicationId], [Key], [Value], [Date])
VALUES (123, 'A', 'abc', '2020-3-1 14:00:01.000')
,(123, 'B', 'abd', '2020-3-1 14:00:02.000')
,(123, 'C', 'abe', '2020-3-1 14:00:03.000')
,(124, 'A', 'abf', '2020-3-1 14:01:00.000')
,(124, 'D', 'abg', '2020-3-1 14:01:01.000');
CREATE TABLE #DataSourcePrepared
(
[ApplicationId] INT
,[ColumnName] VARCHAR(32)
,[Value] VARCHAR(32)
)
INSERT INTO #DataSourcePrepared ([ApplicationId], [ColumnName], [Value])
SELECT [ApplicationId]
,[Key]
,[value]
FROM #DataSource
UNION ALL
SELECT [ApplicationId]
,[Key] + '_Date'
,CONVERT(VARCHAR(19), [Date], 121)
FROM #DataSource;
DECLARE #DymanimcTSQLSatement NVARCHAR(MAX)
,#DynamicColumns NVARCHAR(MAX);
SET #DynamicColumns = STUFF
(
(
SELECT ',' + QUOTENAME([ColumnName])
FROM #DataSourcePrepared
GROUP BY [ColumnName]
ORDER BY [ColumnName]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,1
,''
);
SET #DymanimcTSQLSatement = N'
SELECT *
FROM #DataSourcePrepared
PIVOT
(
MAX([value]) FOR [ColumnName] IN (' + #DynamicColumns +')
) PVT;';
EXECUTE sp_executesql #DymanimcTSQLSatement;
You just need to prepare the data before the actual PIVOT. Also, note that I am ordering the columns when I am building the dynamic part by name. In your real case, you may want to change this to something complex.
you can try this
DECLARE #_cols AS NVARCHAR(MAX) =''
DECLARE #_sql AS NVARCHAR(MAX)
SELECT
#_cols +=','+ QUOTENAME([Key]) + ',' + QUOTENAME([Key]+'_Date')
FROM
(SELECT DISTINCT [Key] FROM ExampleTbl) T
SET #_cols = STUFF(#_cols,1,1,'')
set #_sql = 'SELECT * FROM (
SELECT ApplicationId, [Key], Value FROM ExampleTbl
UNION ALL
SELECT ApplicationId, [Key] + ''_Date'' AS [Key], CONVERT(VARCHAR(30), [Date],121 ) AS Value FROM ExampleTbl
) SRC
PIVOT (MAX(Value) FOR [Key] IN ('+#_cols +' )) AS PVT';
EXEC(#_sql)
Result:
ApplicationId A A_Date B B_Date C C_Date D D_Date
------------- ------- --------------------------- ---------- -------------------------- ------------ ------------------------- ------- -------------------------
123 abc 2020-03-01 14:00:01.000 abd 2020-03-01 14:00:02.000 abe 2020-03-01 14:00:03.000 NULL NULL
124 abf 2020-03-01 14:01:00.000 NULL NULL NULL NULL abg 2020-03-01 14:01:01.000
I've seen just about every kind of pivot example on the Internet, both text based tutorial and video. Not one is solving the issue at hand.
What I want is to pivot the following table:
Sales Table
SalesId | SalesDate | SalesLocation | SalesAmount
-----------------------------------------------------
1 | 2012-03 | New York, NY | 3,000
2 | 2012-04 | Miami, FL | 2,500
3 | 2012-05 | Carmel, CA | 2,850
4 | 2012-06 | Berkeley, CA | 1,900
5 | 2012-07 | Akron, OH | 4,200
6 | 2012-08 | Portland, OR | 2,200
I would like to PIVOT this table to show each row as a column, not distinct SUM of columns. Each row is specifically it's own column, with the date as the header, as if the table has been turned 90 degrees clockwise like an Excel spreadsheet, for date forecasting:
Account Info | 2012-03 | 2012-04 | 2012-05 | 2012-06
---------------------------------------------------------------------
SalesId | 1 | 2 | 3 | 4
SalesLocation | New York, NY | Miami, FL | Carmel, CA | Berkeley, CA
SalesAmount | 3,000 | 2,500 | 2,850 | 1,900
Most of the tutorials on this subject involve creating sums of several rows that have either the same city, the same status or the same type.
For this situation, each row already has a distinct unique date that will never be duplicated, so all records are unique and therefore do not require a function like SUM.
So far, after viewing an incredibly clear solution by JoyceW on the PIVOT Using Date Column thread at the ASP.net forums, I have gotten this far:
declare #cols varchar(max)
select #cols = (select distinct SalesDate from SalesTable for xml path(''))
select #cols = replace(#cols, '', '[')
select #cols = replace(#cols, '', '],')
select #cols = left(#cols, len(#cols) - 1)
declare #query varchar(max)
select #query = 'select * from (select SalesId, SalesLocation, SalesAmount
from SalesTable) src pivot (max(SalesAmount) for SalesDate in ('
+ #cols + ')) piv;'
execute(#query)
While this is not what I was looking for, it's the only tutorial that has allowed me to actually return a result set where the top columns are actually the dates (yay), as seen below:
SalesId | SalesLocation | SalesAmount | 2012-03 | 2012-04 | 2012-05
1 | New York, NY | 3,000 | {null} | {null} | 4
2 | Miami, FL | 2,500 | {null} | 3 | {null}
3 | Carmel, CA | 2,850 | {null} | {null} | {null}
4 | Berkeley, CA | 1,900 | 1 | {null} | {null}
5 | Akron, OH | 4,200 | {null} | {null} | {null}
6 | Portland, OR | 2,200 | {null} | 2 | {null}
Not really sure what's going on here, but it's a lot closer than I was before, I'm actually receiving a result set. Any ideas about how to fine tune this where the rows showing up need to be rotated or pivoted as well?
It seems that I'm only pivoting the headers and not the entire table as I would like. Any suggestions would be greatly appreciated.
As you want multiple aggregation columns in your pivot you have to do the iterations for each aggregation value. I am using Sales as the table name. Please change the table name if it is different for you. Below query should give you the result you want.
DECLARE #cols AS NVARCHAR(MAX),
#Convertcols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#SQL AS NVARCHAR(MAX),
#PivotColumn Varchar(100),
#i Int = 1,
#AggColumn Varchar(100)
DECLARE #Columns TABLE (ID int IDENTITY(1,1), AccountInfo Varchar(max))
SELECT #cols = STUFF((SELECT ', '+ QUOTENAME(SalesDate)
from Sales
group by SalesDate
order by SalesDate
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #Convertcols = STUFF((SELECT ', CAST( '+ QUOTENAME(SalesDate) + ' AS VARCHAR(max)) AS ' + QUOTENAME(SalesDate)
from Sales
group by SalesDate
order by SalesDate
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
INSERT INTO #Columns
SELECT C.name
FROM SYS.COLUMNS C
INNER JOIN SYS.TABLES T ON C.OBJECT_ID = T.OBJECT_ID
WHERE T.NAME = 'Sales'
AND C.name <> 'SalesDate'
While #i <= (SELECT MAX(ID) FROM #Columns)
BEGIN
SELECT #AggColumn = AccountInfo FROM #Columns Where ID = #i
set #query = 'SELECT AccountInfo,' + #Convertcols +
' FROM
(
SELECT ''' + #AggColumn + ''' AS AccountInfo, SalesDate, '+ #AggColumn +'
FROM Sales
) X
PIVOT
(
Max('+ #AggColumn +')
FOR SalesDate in (' + #cols + ')
) P '
SET #SQL = CONCAT(#SQL, CHAR(10), CASE WHEN #i = 1 THEN '' ELSE 'UNION ' END, CHAR(10) , #query)
SET #i = #i+1
END
EXECUTE (#SQL)
Result:
In order for you to be able to PIVOT, you'll need to have at least one non-pivoted column - something which your model is lacking.
Documentation: https://technet.microsoft.com/en-us/library/ms177410%28v=sql.105%29.aspx?f=255&MSPPError=-2147217396
I have a large file that has the following fields:
Table 1:
+---------+--------+-----------+
| User_Id | Key_Id | Value |
+---------+--------+-----------+
| 100 | 74 | 37 |
| 100 | 65 | Male |
| 100 | 279 | G235467 |
+---------+--------+-----------+
and I have another file that tells what each 'Key_Id' is called (they are column names) e.g.
Table 2:
+--------+------------------+
| Key_Id | Key |
+--------+------------------+
| 65 | Gender |
| 66 | Height |
| 74 | Age |
| 279 | ReferenceNo |
I want to create a table using the Key_Id names found in the Key column of table 2, transpose all of the values from table 1 into table 2, but also include the User_Id from table 1 as this relates to an individual.
PS. Table 2 has nearly 300 keys that would need turning into individual fields
So ultimately I would like a table that looks like this:
+---------+---------+--------+-------+--------------+--------+
| User_Id | Gender | Height | Age | ReferenceNo | etc |
+---------+---------+--------+-------+--------------+--------+
| 100 | Male | | 37 | G235467 | |
So that each User_Id is a row and that all the Keys are columns with their respective values
You can use a dynamic sql query as below.
Query
declare #sql as varchar(max);
select #sql = 'select t1.[User_Id], ' + stuff((select +
', max(case t2.[Key_Id] when ' + cast([Key_Id] as varchar(100)) +
' then t1.[Value] end) as [' + [Key] + '] '
from Table2
for xml path('')
), 1, 2, '') +
'from Table1 t1 left join Table2 t2 on t1.[Key_Id] = t2.[Key_Id] group by t1.[User_Id];'
exec(#sql);
Find a demo here
You need to get a coma-separated list of those 300 key names to be used in PIVOT/UNPIVOT operators in T-SQL like described here
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot
you can use pivot as below:
Select * from (
Select u.UserId, k.[key], u.[Value] from table1 u
join table2 k on u.keyid = k.keyid ) a
pivot ( max([Value]) for [key] in ([Gender], [Height], [Age], [ReferenceNo]) ) p
For dynamic list of keys you can use dynamic sql as below:
Declare #cols1 varchar(max)
Declare #query nvarchar(max)
Select #cols1 = stuff((select ','+QuoteName([Key]) from table2 group by [Key] for xml path('')),1,1,'')
Set #Query = 'Select * from (
Select u.UserId, k.[key], u.[Value] from table1 u
join table2 k on u.keyid = k.keyid ) a
pivot ( max([Value]) for [key] in (' + #cols1 + ') ) p '
Select #Query --Check the generated query and execute by uncommenting below query
--exec sp_executesql #Query
This question already has answers here:
SQL Server: Examples of PIVOTing String data
(7 answers)
Closed 8 years ago.
I have a situation like this
+---------+-----------+------------+
| FieldNo | FieldName | Substring |
+---------+-----------+------------+
| 1 | A | 8 |
| 1 | A | A |
| 1 | A | DC |
| 2 | B | 7 |
| 3 | C | 22 |
| 3 | C | 37 |
+---------+-----------+------------+
Need output like this:
+----+------+------+
| A | B | C |
+----+------+------+
| 8 | 7 | 22 |
| A | Null | 37 |
| DC | Null | Null |
+----+------+------+
Any suggestions how I can do this in SQL Server?
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Field_name)
from bear_crossjoin
group by FIELD_NAME, FIELDNUMBER
order by FIELDNUMBER
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N' from
(
select substring, Field_name
from bear_crossjoin
) x
pivot
(
max(substring)
for field_name in (' + #cols + N')
) p '
exec sp_executesql #query
I've assumed the table name as tblTemp. Try this
DECLARE #colList NVARCHAR(max)
DECLARE #query NVARCHAR(max)
select #colList = coalesce(#colList + ',', '') + convert(varchar(12),TT.FIELDNAME)
from (SELECT DISTINCT FIELDNAME FROM tblTemp) TT
order by TT.FIELDNAME
SET #query = 'SELECT ' + #colList + ' FROM
(
SELECT row_number() over(partition by FIELDNO
order by FIELDNO) seq,
FieldName, [Substring]
FROM tblTemp ) als
PIVOT
( MAX([SUBSTRING])
FOR FieldName IN (' + #colList + ')
) piv'
exec sp_executesql #query
fiddle
It seems you are trying to PIVOT by row number instead of directly on the field names. The approach below pivots using the row number to get the desired output:
DECLARE #Data TABLE (FieldNo INT, FieldName VARCHAR(50), [Substring] VARCHAR(500))
INSERT #Data VALUES
(1, 'A', '8'),
(1, 'A', 'A'),
(1, 'A', 'DC'),
(2, 'B', '7'),
(3, 'C', '22'),
(3, 'C', '37')
;WITH DataRows AS (
SELECT
FieldName,
[Substring],
ROW_NUMBER() OVER (PARTITION BY FieldNo ORDER BY FieldName, [Substring]) AS RowNum
FROM #Data
)
SELECT
CONVERT(VARCHAR(10), [A]) AS [A],
CONVERT(VARCHAR(10), [B]) AS [B],
CONVERT(VARCHAR(10), [C]) AS [C]
FROM DataRows
PIVOT (MAX([Substring]) FOR FieldName IN ([A], [B], [C])) T
This yields the desired output:
A B C
---------- ---------- ----------
8 7 22
A NULL 37
DC NULL NULL
I have a table with four columns item_id, color, size, weight, I want to show my table rows into one row like item1,color1,size1,weight1,item2,color2,...........,item4,color4,size4,weight4 ...
Following is my table
+---------+--------+--------+--------+
| item_id | color | size | weight |
+---------+--------+--------+--------+
| 1 | blue | large | 65 |
| 2 | orange | large | 57 |
| 3 | red | small | 12 |
| 4 | violet | medium | 34 |
My desired result will be
+---------+--------+--------+--------++---------+--------+--------+
| item_id1| color1| size1 | weight1| item_id2 | color2 | size2 | weight2 |....
+---------+--------+--------+--------+---------+--------+--------+---------------
| 1 | blue | large| 65 | 2 | orange | large | 57 |...
+---------+--------+--------+--------+ +---------+--------+--------+--------+
Thanks in advance.
In order to get this result, you will need to do a few things:
UNPIVOT the current data
PIVOT the result from the unpivot
use dynamic SQL since you will have an unknown number of rows
Since you are using SQL Server 2005+ you can use CROSS APPLY to unpivot the data, this process takes your multiple columns of item_id, color, size and weight and converts them into multiple rows:
select col+'_'+cast(seq as varchar(50)) col,
value
from
(
select item_id as seq, item_id, color, size, weight
from yourtable
) d
cross apply
(
values
('item_id', cast(item_id as varchar(50))),
('color', color),
('size', size),
('weight', cast(weight as varchar(50)))
) c (col, value);
See SQL Fiddle with Demo. This gives a result:
| COL | VALUE |
----------------------
| item_id_1 | 1 |
| color_1 | blue |
| size_1 | large |
| weight_1 | 65 |
| item_id_2 | 2 |
| color_2 | orange |
| size_2 | large |
| weight_2 | 57 |
| item_id_3 | 3 |
As you can see from the result you now have multiple rows in based off your original data. The COL values are the values that you will use to PIVOT. The full dynamic SQL code will be similar to the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(col+'_'+cast(item_id as varchar(10)))
from yourtable
cross apply
(
select 'item_id', 0 union all
select 'color', 1 union all
select 'size', 2 union all
select 'weight', 3
) c (col, so)
group by item_id, col, so
order by item_id, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #cols + '
from
(
select col+''_''+cast(seq as varchar(50)) col,
value
from
(
select item_id as seq, item_id, color, size, weight
from yourtable
) d
cross apply
(
values
(''item_id'', cast(item_id as varchar(50))),
(''color'', color),
(''size'', size),
(''weight'', cast(weight as varchar(50)))
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query);
See SQL Fiddle with Demo. The final result is:
| ITEM_ID_1 | COLOR_1 | SIZE_1 | WEIGHT_1 | ITEM_ID_2 | COLOR_2 | SIZE_2 | WEIGHT_2 | ITEM_ID_3 | COLOR_3 | SIZE_3 | WEIGHT_3 | ITEM_ID_4 | COLOR_4 | SIZE_4 | WEIGHT_4 |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | blue | large | 65 | 2 | orange | large | 57 | 3 | red | small | 12 | 4 | violet | medium | 34 |
If you want to do it programmatically and you don't know the number of rows try this :
DECLARE #I INT, #END INT, #DATA nvarchar(max), #TEMPSTR nvarchar(max), #DynamicTableSQL nvarchar(max)
SET #I = 1
SET #DATA = ''
SET #TEMPSTR = ''
SELECT #END = MAX(item_id) from items
SET #DynamicTableSQL = 'DECLARE #DynamicTable TABLE('
WHILE #I <= #END
BEGIN
--SELECT #I
SET #TEMPSTR = (select CAST(item_id as nvarchar) + ',''' + color + ''',''' + size + ''',' + cast(weight as nvarchar) + ',' FROM items WHERE item_id = #I)
SET #DynamicTableSQL = #DynamicTableSQL + 'item_id_' + CAST(#I AS VARCHAR(10))+ ' INT ,' + 'color_' + CAST(#I AS VARCHAR(10))+ ' NVARCHAR(15) ,'+ 'size_' + CAST(#I AS VARCHAR(10))+ ' NVARCHAR(15) ,'+ 'weight_' + CAST(#I AS VARCHAR(10))+ ' INT ,'
SET #DATA += #TEMPSTR
SELECT #I = #I + 1
END
SET #DynamicTableSQL = SUBSTRING(#DynamicTableSQL, 0, LEN(#DynamicTableSQL))
SET #DynamicTableSQL = #DynamicTableSQL + ') '
SET #DATA = SUBSTRING(#DATA, 0, LEN(#DATA))
SET #DynamicTableSQL = #DynamicTableSQL + ' INSERT INTO #DynamicTable VALUES (' + #DATA + ')'
SET #DynamicTableSQL = #DynamicTableSQL + ' SELECT * FROM #DynamicTable '
EXEC SP_EXECUTESQL #DynamicTableSQL