SQL Pivoting or Transposing or ... column to row? - sql

I have a question and this looks way better in SQLfiddle:
http://www.sqlfiddle.com/#!3/dffa1/2
I have a table with multirows for each user with datestamp and test results and i would like to transpose or pivot it into one line result as follows where each user has listed all time and value results:
USERID PSA1_time PSA1_result PSA2_time PSA2_result PSA3_time PSA3_result ...
1 1999-.... 2 1998... 4 1999... 6
3 1992... 4 1994 6
4 2006 ... 8
Table below:
CREATE TABLE yourtable
([userid] int, [Ranking] int,[test] varchar(3), [Date] datetime, [result] int)
;
INSERT INTO yourtable
([userid], [Ranking],[test], [Date], [result])
VALUES
('1', '1', 'PSA', 1997-05-20, 2),
('1', '2','PSA', 1998-05-07, 4),
('1', '3','PSA', 1999-06-08, 6),
('1', '4','PSA', 2001-06-08, 8),
('1', '5','PSA', 2004-06-08, 0),
('3', '1','PSA', 1992-05-07, 4),
('3', '2','PSA', 1994-06-08, 6),
('4', '1','PSA', 2006-06-08, 8)
;

Since you want to PIVOT two columns my suggestion would be to unpivot the date and result columns first, then apply the PIVOT function.
The unpivot process will convert the two columns date and result into multiple rows:
select userid,
col = test +'_'+cast(ranking as varchar(10))+'_'+ col,
value
from yourtable t1
cross apply
(
select 'time', convert(varchar(10), date, 120) union all
select 'result', cast(result as varchar(10))
) c (col, value)
See Demo. This will give you a result:
| USERID | COL | VALUE |
--------------------------------------
| 1 | PSA_1_time | 1997-05-20 |
| 1 | PSA_1_result | 2 |
| 1 | PSA_2_time | 1998-05-07 |
| 1 | PSA_2_result | 4 |
| 1 | PSA_3_time | 1999-06-08 |
Now that you have the data in this format, then you can apply pivot to get the max/min value for each item in col:
If you have a limited number of columns, then you can hard-code the query:
select *
from
(
select userid,
col = test +'_'+cast(ranking as varchar(10))+'_'+ col,
value
from yourtable t1
cross apply
(
select 'time', convert(varchar(10), date, 120) union all
select 'result', cast(result as varchar(10))
) c (col, value)
) d
pivot
(
max(value)
for col in (PSA_1_time, PSA_1_result,
PSA_2_time, PSA_2_result,
PSA_3_time, PSA_3_result,
PSA_4_time, PSA_4_result,
PSA_5_time, PSA_5_result)
) piv;
See SQL Fiddle with Demo
If you have unknown columns, then you will need to use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(test +'_'+cast(ranking as varchar(10))+'_'+ col)
from yourtable
cross apply
(
select 'time', 1 union all
select 'result', 2
) c (col, so)
group by test, ranking, col, so
order by Ranking, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT userid,' + #cols + '
from
(
select userid,
col = test +''_''+cast(ranking as varchar(10))+''_''+ col,
value
from yourtable t1
cross apply
(
select ''time'', convert(varchar(10), date, 120) union all
select ''result'', cast(result as varchar(10))
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo. Both versions will give a result:
| USERID | PSA_1_TIME | PSA_1_RESULT | PSA_2_TIME | PSA_2_RESULT | PSA_3_TIME | PSA_3_RESULT | PSA_4_TIME | PSA_4_RESULT | PSA_5_TIME | PSA_5_RESULT |
------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | 1997-05-20 | 2 | 1998-05-07 | 4 | 1999-06-08 | 6 | 2001-06-08 | 8 | 2004-06-08 | 0 |
| 3 | 1992-05-07 | 4 | 1994-06-08 | 6 | (null) | (null) | (null) | (null) | (null) | (null) |
| 4 | 2006-06-08 | 8 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | (null) |

Related

SQL Server recursive query to show path of parents

I am working with SQL Server statements and have one table like:
| item | value | parentItem |
+------+-------+------------+
| 1 | 2test | 2 |
| 2 | 3test | 3 |
| 3 | 4test | 4 |
| 5 | 1test | 1 |
| 6 | 3test | 3 |
| 7 | 2test | 2 |
And I would like to get the below result using a SQL Server statement:
| item1 | value1 |
+-------+--------------------------+
| 1 | /4test/3test/2test |
| 2 | /4test/3test |
| 3 | /4test |
| 5 | /4test/3test/2test/1test |
| 6 | /4test/3test |
| 7 | /4test/3test/2test |
I didn't figure out the correct SQL to get all the values for all the ids according to parentItem.
I have tried this SQL :
with all_path as
(
select item, value, parentItem
from table
union all
select a.item, a.value, a.parentItem
from table a, all_path b
where a.item = b.parentItem
)
select
item as item1,
stuff(select '/' + value
from all_path
order by item asc
for xml path ('')), 1, 0, '') as value1
from
all_path
But got the "value1" column in result like
/4test/4test/4test/3test/3test/3test/3test/2test/2test/2test/2test
Could you please help me with that? Thanks a lot.
based on the expected output you gave, use the recursive part to concatenate the value
;with yourTable as (
select item, value, parentItem
from (values
(1,'2test',2)
,(2,'3test',3)
,(3,'4test',4)
,(5,'1test',1)
,(6,'3test',3)
,(7,'2test',2)
)x (item,value,parentItem)
)
, DoRecursivePart as (
select 1 as Pos, item, convert(varchar(max),value) value, parentItem
from yourTable
union all
select drp.pos +1, drp.item, convert(varchar(max), yt.value + '/' + drp.value), yt.parentItem
from yourTable yt
inner join DoRecursivePart drp on drp.parentItem = yt.item
)
select drp.item, '/' + drp.value
from DoRecursivePart drp
inner join (select item, max(pos) mpos
from DoRecursivePart
group by item) [filter] on [filter].item = drp.item and [filter].mpos = drp.Pos
order by item
gives
item value
----------- ------------------
1 /4test/3test/2test
2 /4test/3test
3 /4test
5 /4test/3test/2test/1test
6 /4test/3test
7 /4test/3test/2test
Here's the sample data
drop table if exists dbo.test_table;
go
create table dbo.test_table(
item int not null,
[value] varchar(100) not null,
parentItem int not null);
insert dbo.test_table values
(1,'test1',2),
(2,'test2',3),
(3,'test3',4),
(5,'test4',1),
(6,'test5',3),
(7,'test6',2);
Here's the query
;with recur_cte(item, [value], parentItem, h_level) as (
select item, [value], parentItem, 1
from dbo.test_table tt
union all
select rc.item, tt.[value], tt.parentItem, rc.h_level+1
from dbo.test_table tt join recur_cte rc on tt.item=rc.parentItem)
select rc.item,
stuff((select '/' + cast(parentItem as varchar)
from recur_cte c2
where rc.item = c2.item
order by h_level desc FOR XML PATH('')), 1, 1, '') [value1]
from recur_cte rc
group by item;
Here's the results
item value1
1 4/3/2
2 4/3
3 4
5 4/3/2/1
6 4/3
7 4/3/2

Pivot rows into columns with fixed rows but unknown content in SQL Server

I've seen lots of questions relating to pivoting rows into columns, but nothing similar enough to my problem to make any headway with it.
I have a dataset that looks something like this:
| candidate | qualification | unit | passed |
---------------------------------------------
| C1 | Q1 | U1-1 | 1 |
| C1 | Q1 | U1-2 | 1 |
| C1 | Q2 | U2-1 | 0 |
| C1 | Q2 | U2-2 | 1 |
| C2 | Q1 | U1-1 | 0 |
| C2 | Q1 | U1-2 | 0 |
| C2 | Q2 | U2-1 | 1 |
| C2 | Q2 | U2-2 | 1 |
where each candidate can be signed up to multiple qualifications, which each have multiple units that can be passed (1) or failed (0).
I need the data to be transformed to look like:
| candidate | qualification | unit_1 | unit_1_passed | unit_2 | unit_2_passed |
-------------------------------------------------------------------------------
| C1 | Q1 | U1-1 | 1 | U1-2 | 1 |
| C1 | Q2 | U2-1 | 0 | U2-2 | 1 |
| C2 | Q1 | U1-1 | 0 | U1-2 | 0 |
| C2 | Q2 | U2-1 | 1 | U2-2 | 1 |
so that the unit for each qualification and if is passed is pivoted into a column.
I know that there will always be fixed number of units per qualification, but I do not know what the unit names will be in advance.
My query currently looks like:
select
candidate,
qualification,
unit,
passed
from exams
but I don't know how to go about pivoting the rows into columns.
Thanks in advance.
You can use window function row_number() to assign a rank to each unit in each candidate/qualification group, and then pivot with conditional aggregation:
select
candidate,
qualification,
max(case when rn = 1 then unit end) unit_1,
max(case when rn = 1 then passed end) unit_1_passed,
max(case when rn = 2 then unit end) unit_2,
max(case when rn = 2 then passed end) unit_2_passed
from (
select
t.*,
row_number() over(
partition by candidate, qualification
order by unit
) rn
from exams t
) t
group by candidate, qualification
This is the best I could come up with
select 'C1' as 'candidate', 'Q1' as 'qualification', 'U1-1' as 'unit', '1' as 'passed' into #tmp union
select 'C1', 'Q1', 'U1-2', '1' union
select 'C1', 'Q2', 'U2-1', '0' union
select 'C1', 'Q2', 'U2-2', '1' union
select 'C2', 'Q1', 'U1-1', '0' union
select 'C2', 'Q1', 'U1-2', '0' union
select 'C2', 'Q2', 'U2-1', '1' union
select 'C2', 'Q2', 'U2-2', '1'
DECLARE #cols AS NVARCHAR(MAX),#colsUnit AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select * from #tmp
DECLARE #UnitNames VARCHAR(8000)
SELECT #UnitNames = COALESCE(#UnitNames + ', ', '') + 'unit_' +unitnumber
FROM (select distinct right(unit,1) unitnumber from #tmp)a
select candidate, unit, qualification, passed, 'unit_'+b.unitnumber as unitnumber into #tmp2 from #tmp a
inner join (select distinct right(unit,1) unitnumber from #tmp) b on right(a.unit,1) = b.unitnumber
where right(unit,1) = unitnumber
order by unitnumber
select * from #tmp2 order by unitnumber
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.unitnumber)
FROM #tmp2 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #colsUnit = STUFF((SELECT distinct ',' + QUOTENAME(c.unitnumber)
FROM #tmp2 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT candidate, qualification, unit,
' + #colsUnit + ' from
(
select candidate
, qualification
, passed
, unit
, unitnumber
from #tmp2
) x
pivot
(
max(passed)
for unitnumber in (' + #colsUnit + ')
) p '
print #query
exec (#query)
drop table #tmp, #tmp2
It yields a table kinda close to yours:
Hope it helps

How do I group pivot results in SQL?

I have been able to combine results using the pivot function. Been trying various examples on my solution to group these results together. Am I doing this wrong or is it a simple fix?
create table DBE_LOCATION
(
REF int,
STATUS varchar(1)
);
insert into DBE_LOCATION values
(1, 'A'),
(2, 'A');
create table SYS_SCREEN_FIELD
(
REF int,
FIELD_DISPLAY varchar(20),
ORDER_BY int
);
insert into SYS_SCREEN_FIELD values
(1, 'Location Name', 0),
(2, 'Address', 1),
(3, 'Suburb', 2),
(4, 'Postcode', 3),
(5, 'State', 4),
(6, 'Country', 5);
create table DBE_LOCATION_DATA
(
REF int,
FIELD_REF int,
LOCATION_REF int,
VALUE_TEXT_FIELD varchar(MAX)
);
insert into DBE_LOCATION_DATA values
(1, 1, 1, 'New York'),
(2, 1, 2, 'Japan'),
(3, 2, 1, '123 Address St'),
(4, 2, 2, '456 Address St');
Now the final thing would be to show a result set of each Location with the field display as the column name. Something like this if using the above example:
Ref Location Name Address Status
1 New York 123 Address St A
2 Japan 456 Address Ave A
Have got the following working in gathering the data and creating the dynamic columns:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(FIELD_DISPLAY)
from SYS_SCREEN_FIELD
group by FIELD_DISPLAY, ORDER_BY
order by ORDER_BY
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT REF, ' + #cols + ', STATUS from
(
select l.REF, l.STATUS,
f.FIELD_DISPLAY,
d.FIELD_REF, d.VALUE_TEXT_FIELD
from DBE_LOCATION l
right join DBE_LOCATION_DATA d
on l.REF = d.LOCATION_REF
inner join SYS_SCREEN_FIELD f
on d.FIELD_REF = f.REF
) x
pivot
(
max(VALUE_TEXT_FIELD)
for FIELD_DISPLAY in (' + #cols + ')
) p'
execute(#query)
Results are not grouped by REF. How is this done?
SQL Fiddle Link
The problem is with the addition of the column FIELD_REF in your subquery. Even though you are not including this column in your final select list, since it is in your subquery the column is used during the grouping of the PIVOT.
You can see the issue if you include it in your final select, you get a result:
| REF | FIELD_REF | LOCATION NAME | ADDRESS | SUBURB | POSTCODE | STATE | COUNTRY | STATUS |
|-----|-----------|---------------|----------------|--------|----------|--------|---------|--------|
| 1 | 1 | Adelaide | (null) | (null) | (null) | (null) | (null) | S |
| 1 | 2 | (null) | 1 Adelaide St | (null) | (null) | (null) | (null) | S |
The FIELD_REF has a value of 1 and 2 for REF=1, when the aggregate and group by are applied, you will return multiple rows.
If you remove this column from your subquery you will get the result that you want:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(FIELD_DISPLAY)
from SYS_SCREEN_FIELD
group by FIELD_DISPLAY, ORDER_BY
order by ORDER_BY
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT REF, ' + #cols + ', STATUS from
(
select l.REF, l.STATUS,
f.FIELD_DISPLAY,
d.VALUE_TEXT_FIELD
from DBE_LOCATION l
right join DBE_LOCATION_DATA d
on l.REF = d.LOCATION_REF
inner join SYS_SCREEN_FIELD f
on d.FIELD_REF = f.REF
) x
pivot
(
max(VALUE_TEXT_FIELD)
for FIELD_DISPLAY in (' + #cols + ')
) p'
execute sp_executesql #query;
See SQL Fiddle with Demo. Now your final result is:
| REF | LOCATION NAME | ADDRESS | SUBURB | POSTCODE | STATE | COUNTRY | STATUS |
|-----|---------------|----------------|--------|----------|--------|---------|--------|
| 1 | Adelaide | 1 Adelaide St | (null) | (null) | (null) | (null) | S |
| 2 | Melbourne | 2 Melbourne St | (null) | (null) | (null) | (null) | S |

Can anyone write query for this?

My table is as below
recordId fwildcardId refNumber wildcardName wildcardValue comments
404450 154834 2 aaa p p
404450 154833 1 aa oi p
406115 154867 1 98 ff ff
406199 154869 1 aa aaaa ssss
406212 154880 1 bbbbb card comm
and I need the output as
RecordId fwildcardid1 refNo1 Name1 Value1 comments1 fwildcardid2 refNo2 Name2 Value2 comments2 fwildcardid3 refNo3 Name3 Value3 comments3
404450 154834 2 aaa p p 154833 1 aa oi p
406115 Null Null Null Null Null Null Null Null Null Null 154867 1 98 ff ff
406199 Null Null Null Null Null 154869 1 aa aaaa ssss Null Null Null Null
I tried pivoting like below , but didnt succeed .
select t1.recordId,t1.wildcardid as fwildcardId,t1.refNo as refNumber,t2.wildcardName,t1.attributeValue as wildcardValue,t1.comments
into #tempp
from fwildcards t1
inner join fwildcardattributes t2 on t2.WildcardID=t1.attributenameid and t2.MarketID=5
inner join fitems t3 on t3.recordid=t1.recordid and t3.marketid=5
order by recordid,attributenameid
select * from #tempp
pivot (min (wildcardValue) for wildcardName in ([aaa],[aa],[aaaa],[98],[kki],[bbbbb],[SUN])) as wildcardValuePivot
In order to get this result, you will have to UNPIVOT and hen PIVOT the data. The UNPIVOT will take the values in the columns fwildcardId, refNumber, wildcardName, wildcardValue and comments and turns them into rows. Once the data is in rows, then you can apply the PIVOT function to get the final result.
To unpivot the data, you can use either the UNPIVOT function or you can use the CROSS APPLY and VALUES clause.
UNPIVOT:
select recordid,
col+cast(rn as varchar(10)) col,
unpiv_value
from
(
select recordid,
cast(fwildcardid as varchar(10)) fwildcardid,
cast(refnumber as varchar(10)) refnumber,
cast(wildcardname as varchar(10)) name,
cast(wildcardvalue as varchar(10)) value,
cast(comments as varchar(10)) comments,
row_number() over(partition by recordid
order by fwildcardid) rn
from tempp
) d
unpivot
(
unpiv_value
for col in (fwildcardid, refnumber, name, value, comments)
) c
See SQL Fiddle with Demo.
CROSS APPLY and VALUES:
select recordid,
col+cast(rn as varchar(10)) col,
value
from
(
select recordid,
cast(fwildcardid as varchar(10)) fwildcardid,
cast(refnumber as varchar(10)) refnumber,
wildcardname,
wildcardvalue,
comments,
row_number() over(partition by recordid
order by fwildcardid) rn
from tempp
) d
cross apply
(
values
('fwildcardid', fwildcardid),
('refnumber', refnumber),
('name', wildcardname),
('value', wildcardvalue),
('comments', comments)
) c (col, value)
See SQL Fiddle with Demo.
These convert the results in a format:
| RECORDID | COL | VALUE |
------------------------------------
| 404450 | fwildcardid1 | 154833 |
| 404450 | refnumber1 | 1 |
| 404450 | name1 | aa |
| 404450 | value1 | oi |
| 404450 | comments1 | p |
| 404450 | fwildcardid2 | 154834 |
When you unpivot data into the same column, it has to be the same datatype. You will notice that I applied a cast to the columns so the datatype is the same.
Once the data is in the row format, you can convert it back into columns with PIVOT:
select *
from
(
select recordid,
col+cast(rn as varchar(10)) col,
unpiv_value
from
(
select recordid,
cast(fwildcardid as varchar(10)) fwildcardid,
cast(refnumber as varchar(10)) refnumber,
cast(wildcardname as varchar(10)) name,
cast(wildcardvalue as varchar(10)) value,
cast(comments as varchar(10)) comments,
row_number() over(partition by recordid
order by fwildcardid) rn
from tempp
) d
unpivot
(
unpiv_value
for col in (fwildcardid, refnumber, name, value, comments)
) c
) src
pivot
(
max(unpiv_value)
for col in (fwildcardid1, refnumber1, name1, value1, comments1,
fwildcardid2, refnumber2, name2, value2, comments2)
) piv;
See SQL Fiddle with Demo.
The above version works great if you have a known number of columns, but if you will have an unknown number of values that will be converted into columns, 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(c.col+cast(rn as varchar(10)))
from
(
select row_number() over(partition by recordid
order by fwildcardid) rn
from tempp
) t
cross apply
(
select 'fwildcardid' col, 1 sortorder union all
select 'refNumber', 2 union all
select 'name', 3 union all
select 'value', 4 union all
select 'comments', 5
) c
group by col, rn, sortorder
order by rn, sortorder
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT recordid,' + #cols + ' from
(
select recordid,
col+cast(rn as varchar(10)) col,
unpiv_value
from
(
select recordid,
cast(fwildcardid as varchar(10)) fwildcardid,
cast(refnumber as varchar(10)) refnumber,
cast(wildcardname as varchar(10)) name,
cast(wildcardvalue as varchar(10)) value,
cast(comments as varchar(10)) comments,
row_number() over(partition by recordid
order by fwildcardid) rn
from tempp
) d
unpivot
(
unpiv_value
for col in (fwildcardid, refnumber, name, value, comments)
) c
) src
pivot
(
max(unpiv_value)
for col in (' + #cols + ')
) p '
execute(#query);
See SQL Fiddle with Demo. Both of these give the result:
| RECORDID | FWILDCARDID1 | REFNUMBER1 | NAME1 | VALUE1 | COMMENTS1 | FWILDCARDID2 | REFNUMBER2 | NAME2 | VALUE2 | COMMENTS2 |
-------------------------------------------------------------------------------------------------------------------------------
| 404450 | 154833 | 1 | aa | oi | p | 154834 | 2 | aaa | p | p |
| 406115 | 154867 | 1 | 98 | ff | ff | (null) | (null) | (null) | (null) | (null) |
| 406199 | 154869 | 1 | kki | aaaa | ssss | (null) | (null) | (null) | (null) | (null) |
| 406212 | 154880 | 1 | bbbbb | card | comm | (null) | (null) | (null) | (null) | (null) |
No Pivot No Cross Apply
According to edited Question.
select
DISTINCT
A.recordId AS recordId,
A1.fwildcardId AS fwildcardId1,
A1.refNumber AS refNumber1,
A1.wildcardName AS wildcardName1,
A1.wildcardValue AS wildcardValue1,
A1.comments AS comments1,
A2.fwildcardId AS fwildcardId2,
A2.refNumber AS refNumber2,
A2.wildcardName AS wildcardName2,
A2.wildcardValue AS wildcardValue2,
A2.comments AS comments2,
A3.fwildcardId AS fwildcardId3,
A3.refNumber AS refNumber3,
A3.wildcardName AS wildcardName3,
A3.wildcardValue AS wildcardValue3,
A3.comments AS comments3,
A4.fwildcardId AS fwildcardId4,
A4.refNumber AS refNumber4,
A4.wildcardName AS wildcardName4,
A4.wildcardValue AS wildcardValue4,
A4.comments AS comments4,
A5.fwildcardId AS fwildcardId5,
A5.refNumber AS refNumber5,
A5.wildcardName AS wildcardName5,
A5.wildcardValue AS wildcardValue5,
A5.comments AS comments5,
A6.fwildcardId AS fwildcardId6,
A6.refNumber AS refNumber6,
A6.wildcardName AS wildcardName6,
A6.wildcardValue AS wildcardValue6,
A6.comments AS comments6,
A7.fwildcardId AS fwildcardId7,
A7.refNumber AS refNumber7,
A7.wildcardName AS wildcardName7,
A7.wildcardValue AS wildcardValue7,
A7.comments AS comments7,
A8.fwildcardId AS fwildcardId8,
A8.refNumber AS refNumber8,
A8.wildcardName AS wildcardName8,
A8.wildcardValue AS wildcardValue8,
A8.comments AS comments8,
A9.fwildcardId AS fwildcardId9,
A9.refNumber AS refNumber9,
A9.wildcardName AS wildcardName9,
A9.wildcardValue AS wildcardValue9,
A9.comments AS comments9,
A10.fwildcardId AS fwildcardId10,
A10.refNumber AS refNumber10,
A10.wildcardName AS wildcardName10,
A10.wildcardValue AS wildcardValue10,
A10.comments AS comments10
from Table_name A
LEFt JOIN Table_name A1 ON A.recordId=A1.recordId AND A1.wildcardName='aaa'
LEFT JOIN Table_name A2 ON A.recordId=A2.recordId AND A2.wildcardName='aa'
LEFT JOIN Table_name A3 ON A.recordId=A3.recordId AND A3.wildcardName='98'
LEFT JOIN Table_name A4 ON A.recordId=A4.recordId AND A4.wildcardName=''
LEFT JOIN Table_name A5 ON A.recordId=A5.recordId AND A5.wildcardName=''
LEFT JOIN Table_name A6 ON A.recordId=A6.recordId AND A6.wildcardName=''
LEFT JOIN Table_name A7 ON A.recordId=A7.recordId AND A7.wildcardName=''
LEFT JOIN Table_name A8 ON A.recordId=A8.recordId AND A8.wildcardName=''
LEFT JOIN Table_name A9 ON A.recordId=A9.recordId AND A9.wildcardName=''
LEFT JOIN Table_name A10 ON A.recordId=A10.recordId AND A10.wildcardName=''
SQL Fiddle

How do I Pivot Vertical Data to Horizontal Data SQL with Variable Row Lengths?

Okay I have the following table.
Name ID Website
Aaron | 2305 | CoolSave1
Aaron | 8464 | DiscoWorld1
Adriana | 2956 | NewCin1
Adriana | 5991 | NewCin2
Adriana | 4563 NewCin3
I would like to transform it into the following way.
Adriana | 2956 | NewCin1 | 5991 | NewCin2 | 4563 | NewCin3
Aaron | 2305 | CoolSave1 | 8464 | DiscoWorld | NULL | NULL
As you can see i am trying to take the first name from the first table and make a single row with all the IDs / Websites associated with that name. The problem is, there is a variable amount of websites that may be associated with each name. To handle this i'd like to just make a table with with the number of fields sequal to the max line item, and then for the subsequent lineitems, plug in a NULL where there are not enough data.
In order to get the result, you will need to apply both the UNPIVOT and the PIVOT functions to the data. The UNPIVOT will take the columns (ID, website) and convert them to rows, once this is done, then you can PIVOT the data back into columns.
The UNPIVOT code will be similar to the following:
select name,
col+'_'+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv;
See SQL Fiddle with Demo. This gives a result:
| NAME | COL | VALUE |
-------------------------------------
| Aaron | id_1 | 2305 |
| Aaron | website_1 | CoolSave1 |
| Aaron | id_2 | 8464 |
| Aaron | website_2 | DiscoWorld1 |
As you can see I applied a row_number() to the data prior to the unpivot, the row number is used to generate the new column names. The columns in the UNPIVOT must also be of the same datatype, I applied a cast to the id column in the subquery to convert the data to a varchar prior to the pivot.
The col values are then used in the PIVOT. Once the data has been unpivoted, you apply the PIVOT function:
select *
from
(
select name,
col+'_'+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv
) d
pivot
(
max(value)
for col in (id_1, website_1, id_2, website_2, id_3, website_3)
) piv;
See SQL Fiddle with Demo.
The above version works great if you have a limited or known number of values. But if the number of rows is unknown, then you will need to use dynamic SQL to generate the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME( col+'_'+cast(col_num as varchar(10)))
from
(
select row_number() over(partition by name order by id) col_num
from yt
) t
cross apply
(
select 'id' col union all
select 'website'
) c
group by col, col_num
order by col_num, col
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT name,' + #cols + '
from
(
select name,
col+''_''+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query);
See SQL Fiddle with Demo. Both versions give the result:
| NAME | ID_1 | WEBSITE_1 | ID_2 | WEBSITE_2 | ID_3 | WEBSITE_3 |
------------------------------------------------------------------------
| Aaron | 2305 | CoolSave1 | 8464 | DiscoWorld1 | (null) | (null) |
| Adriana | 2956 | NewCin1 | 4563 | NewCin3 | 5991 | NewCin2 |