T-SQL:Transform variable number of rows into columns - sql

When I run a SQL query which returns one column with variable number of rows returned, I'd like to transform each of the row into column VALUE (I don't mind what the column header/titles are).
E.g.
Column1
-------
a
b
c
d
e
I want a script which will transform the above into a table like:
Col1 Col2 Col3 Col4 Col5
------------------------
a b c d e
(Note that I do not care for the column names).
I know I cannot user PIVOT as row numbers are not fixed (they are based on a SQL query).
Any ideas?
Thanks!

You're trying to pivot your results and include a counter in your column name. Since I'm presuming you don't know the potential number of columns, you'll need to use Dynamic SQL to accomplish this.
This should be close using ROW_NUMBER to get the counter:
declare #cols AS NVARCHAR(MAX),
#colswithalias AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
set #colswithalias = STUFF((SELECT distinct ',' + QUOTENAME(col1)
+ ' AS Col'
+ CAST(ROW_NUMBER() OVER (ORDER BY col1) as varchar(10))
FROM yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #cols = STUFF((SELECT distinct ',' + QUOTENAME(col1)
FROM yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #colswithalias + '
from
(
select col1 rn, col1
from yourtable
) x
pivot
(
max(rn)
for col1 in (' + #cols + ')
) p '
execute(#query)
SQL Fiddle Demo

Related

The type of column "Date" conflicts with the type of other columns specified in the UNPIVOT list

I have the following code to do Pivot and Unpivot on a set of columns:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#colsUnpivot AS NVARCHAR(MAX)
select #colsUnpivot = stuff((select ','+quotename(C.name)
from tempdb.sys.columns as C
where C.object_id = object_id('tempdb..#TmpTable')
for xml path('')), 1, 1, '')
SET #cols = STUFF((SELECT ',' + QUOTENAME(a.Date)
FROM
(Select top 10000 date from
#TmpTable
order by date) a
group by a.Date
order by a.Date
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT name, ' + #cols + ' from
(
select Date,name,value
from #TmpTable
unpivot
(
value for name in ('+#colsUnpivot+')
) unpiv
) x
pivot
(
sum(value)
for date in (' + #cols + ')
) p '
exec(#query)
But, I keep getting these errors which I can't figure out why:
The type of column "Date" conflicts with the type of other columns specified in the UNPIVOT list.
Invalid column name 'Date'
The type of Date column in the temp table is datetime.
This post was very helpful to explain the issue. Basically, I had to convert the values to decimal for all the columns in the inner select statement of the unpivot section:
Error : The type of column "DOB" conflicts with the type of other columns specified in the UNPIVOT list

SQL Server: case/if else -select and apply function only if present in table

I have the following dynamic query that creates a pivoted table for each account_id against the products using an UDF. I need to add spaces after the UDF is executed depending up the account_id being matched to the specific tables. This works perfectly fine, and returns the 2nd table in the image, I just want to add some condition where it checks for account id's present in other tables and then adds spaces to output from the UDF eg- the account id in the pivot matches the id present in test_rev then 2 spaces if the account_id in the pivot matches the id present in test_oncontract then 3 spaces so on
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.A_NAME)
FROM TEST_11 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT account_id, ' + #cols + ' INTO TEST_DETAIL from
(
select account_id
, dbo.make_table(apple,ball,cat,dog) AS newvalue
,a_name
from test_sample
) x
pivot
(
MAX(newvalue)
for a_name in (' + #cols + ')
) p '
execute(#query)
Image below shows how make_table udf converts the 1st table into 2nd just picking up the initials from each column name from the 1st table
I was able to call my function and add the required spaces withing the select.
But the case statement just executes the first condition and I cant get the records from the other tables. How can I implement if conditions instead of the case statements to to get data depending on all four conditions. Below is the code I am currently using:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.a_name)
FROM CRS_PRODLINE c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT account_id, ' + #cols + ' INTO TEST_DETAIL from
(select account_id,
(case
when exists (select account_id from [dbo].[TEST_R6])
then
dbo.make_sam_indicator112(apple,ball,cat,dog) + space(1) + ''rr''
when exists (select account_id from tbl_noR6)
then
dbo.make_sam_indicator112(apple,ball,cat,dog) + space(2) + ''cc''
when exists (select account_id from tbl_acct)
then
dbo.make_sam_indicator112(apple,ball,cat,dog) + space(3) + ''pp''
when exists (select account_id from test_NA)
then
dbo.make_sam_indicator112(apple,ball,cat,dog) + space(4) + ''no''
end) as newvalue,
a_name
from CRS_PRODLINE
) x
pivot
(
MAX(newvalue)
for a_name in (' + #cols + ')
) p '
execute(#query)

SQL query unknown rows into columns

I asked this question and it was marked as a duplicate of How to pivot unknown number of columns & no aggregate in SQL Server?, but that answer doesn't help me.
I have a table of data that looks like this, with an unknown number of rows and values.
RecID Name Value
1 Color Red
2 Size Small
3 Weight 20lbs
4 Shape Square
I need a query that will return the data like this, building out a column for each row. I cannot hard code anything except the column headers 'Name' and 'Value'.
Color Size Weight Shape
Red Small 20lbs Square
Here is what I have so far that is partly working:
INSERT INTO #Table VALUES
(1,'Color' ,'Red'),
(2,'Size' ,'Small'),
(3,'Weight','20lbs'),
(4,'Shape' ,'Square')
;with mycte
as
(
SELECT rn,cols,val
FROM (SELECT row_number() over(order by Name) rn, Name, Value
FROM #Table) AS src1
UNPIVOT (val FOR cols
IN ( [Name], [Value])) AS unpvt
)
SELECT *
FROM (SELECT rn,cols,val
FROM mycte) AS src2 PIVOT
( Max(val) FOR rn IN ([1], [2], [3])) AS pvt
Which returns:
cols 1 2 3
Name Color Shape Size
Value Red Square Small
Two problems with this that I can't seem to resolve.
I don't need the column headers and the first column that has cols, Name, Value in it.
Can't figure out how to have it build a column for each row without specifying the [x] identifiers.
Any guidance would be great I've been stuck on this a while now.
declare #collist nvarchar(max)
SET #collist = stuff((select distinct ',' + QUOTENAME(name)
FROM #t -- your table here
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
declare #q nvarchar(max)
set #q = '
select *
from (
select rn, name, Value
from (
select *, row_number() over (partition by name order by RecID desc) as rn
from #t -- your table here
) as x
) as source
pivot (
max(Value)
for name in (' + #collist + ')
) as pvt
'
exec (#q)
Until now, I have reached to following code, hope it helps you,
Current outpu comes as
Color Shape Size Weight
Red NULL NULL NULL
NULL NULL Small NULL
NULL NULL NULL 20lbs
NULL Square NULL NULL
Create table DyTable
(
tid int,
Name varchar(20),
Value varchar(20)
)
INSERT INTO DyTable VALUES
(1,'Color' ,'Red'),
(2,'Size' ,'Small'),
(3,'Weight','20lbs'),
(4,'Shape' ,'Square')
DECLARE #Cols NVARCHAR(MAX);
DECLARE #Cols1 NVARCHAR(MAX);
SELECT #Cols = STUFF((
SELECT DISTINCT ', ' + QUOTENAME(Name)
FROM DyTable
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,2,'')
,#Cols1 = STUFF((
SELECT DISTINCT ', max(' + QUOTENAME(Name) + ') as ' + Name
FROM DyTable
FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,2,'')
DECLARE #Sql NVARCHAR(MAX)
Select #Cols
SET #Sql = 'Select '+ #Cols1 +'
from (SELECT ' + #Cols + '
FROM DyTable t
PIVOT (MAX(Value)
FOR Name
IN (' + #Cols + ')
)P)a'
EXECUTE sp_executesql #Sql

SQL inserting numerous columns for matrix

Is there any quick way I could transpose values in a row to column headers.. say I have row values A, B, C ... Z in a column called indx_nm. Is there a easy way to make column headers A, B, C ... Z without having to manually populate this (I have 1000 distinct values that I meet to make a covariance matrix out of)
You may use dynamic PIVOT.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT ',' + CONVERT(VARCHAR,indx_nm)
FROM TableName c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #cols + ' from (
select indx_nm,
Othercolumn
from temp
) x
pivot
(
max(Othercolumn)
for indx_nm in (' + #cols + ')
) p '
EXECUTE #query

while converting column to row not able to fetch value from another table automatically

select *
from (
select vtid, convert(date, dtime) as Date from Transaction_tbl where locid = 5
) as vt
pivot (
count(vtid)
for vtid in (select vtid from VType_tbl)
) as pvt
while executing this query am getting error
Incorrect syntax near the keyword 'select'." and Incorrect syntax near
')'.
actually I have one more table,name= Vtype_table , How Can I load all vtid from vtype table in this query? I want to get output depend upon vtid.
Any help greatly appreciated.
Your PIVOT syntax is correct except you are using a SELECT statement inside your PIVOT.
You cannot use a SELECT statement inside the PIVOT IN clause to select column headers. It is required that the columns for the IN clause be known prior to executing the query.
If you are looking to generate a dynamic list of vtid values, then you will need to use dynamic SQL to get the result and the syntax will be similar to the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(vtid)
from VType_tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Date, ' + #cols + '
from
(
select vtid, convert(date, dtime) as Date
from Transaction_tbl
where locid = 5
) d
pivot
(
count(vtid)
for vtid in (' + #cols + ')
) p '
execute(#query);
Edit, if you want the type names to appear then you should be able to use the following:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(vt_name)
from VType_tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Date, ' + #cols + '
from
(
select v.vt_name, convert(date, dtime) as Date
from Transaction_tbl t
inner join VType_tbl v
on t.vtid = v.vtid
where locid = 5
) d
pivot
(
count(vt_name)
for vt_name in (' + #cols + ')
) p '
execute(#query)
Note: I am guessing on the column name for VType_tbl