I have a Problem converting rows in columns of a SQL Result.
My structure is like this:
GUID | PropertyName | PropertyValue
abcd | DistinguishedName | cn=abcd...
abcd| CN | cn= GROUP_
abcd| Operation | ADD
1231 | DistinguishedName| cn=123dd
1231 | Cn | cn=ASDGRUOP
1231 | Operation | DEL
There can be n PropertyNames that I dont know before, they are dynamically - i can get them through an SQL, that is not the Problem.
I want to have a structure like this:
GUID | DistinguishedName | CN | Operation
abcd| cn=abcd...| cn= GROUP_ | ADD
1231 | cn=123dd | cn=ADSGROUP | DEL
and so on.
The Column-Headers i get by this SQL:
select #cols = STUFF (( SELECT DISTINCT '],[' + x.ParameterName from ... and parametername in ('PropertyValue','DistinguishedName', 'Operation')
FOR XML PATH ('')),1,2,'') + ']'
I can do this with PIVOT-Function but because i dont have Aggregation, I cant get the right result:
set #query = N'SELECT '+ #cols + ' FROM (
SELECT x.parametervalue, x.parametername
from ... and parametername in (''PropertyValue'',''DistinguishedName'', ''Operation'')
) a
PIVOT (max(a.parametervalue) FOR ParameterName in ( ' + #cols + ')) as pv;'
exec sp_executesql #query;
I get the following result:
GUID | DistinguishedName | CN | Operation | ... other Propertys
abcd | cn=abcd... | cn = GROUP_ |ADD |...
Only 1 Result - not more. But there are like 700 Results from this query, because of the MAX() function i get only one. How can I get a Pivot without Aggregation to get all of the results?
Thank you in Advance!
Here is the dynamic PIVOT query:
DECLARE #sql NVARCHAR(MAX),
#cols NVARCHAR(MAX);
SELECT #cols =
STUFF((
SELECT DISTINCT ',' + QUOTENAME(PropertyName)
FROM #tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SELECT #sql =
'SELECT GUID, ' + #cols + '
FROM (
SELECT
GUID, PropertyName, PropertyValue
FROM #tbl
) t
PIVOT
(
MAX(PropertyValue)
FOR PropertyName IN(' + #cols + ')
) p ';
PRINT (#sql);
EXEC (#sql);
ONLINE DEMO
Another way to achieve the desired result is to use a dynamic crosstab:
DECLARE #sql NVARCHAR(MAX);
SELECT #sql =
'SELECT
GUID' + CHAR(10) +
(SELECT DISTINCT
' , MAX(CASE WHEN PropertyName = ''' + PropertyName + ''' THEN PropertyValue END) AS ' + QUOTENAME(PropertyName) + CHAR(10)
FROM #tbl
FOR XML PATH('')
) +
'FROM #tbl
GROUP BY GUID;';
PRINT (#sql);
EXEC (#sql);
ONLINE DEMO
Related
Morning all, Longtime lurker, first time poster.
I'm writing a stored procedure to take the results from one SELECT statement and use that output to build another SELECT statement. Trouble is I can not find a mechanism or code to accomplish this. Assigning the results to a variable doesn't seem to be an option because SQL doesn't support Arrays (that I know of).
+----+-------------+-------------+
| ID | ___$seqval | Column_Name |
+----+-------------+-------------+
| 1 | 0x000000E10 | EnvType |
| 2 | 0x000000E10 | DataType |
| 3 | 0x000000E10 | DateMod |
+----+-------------+-------------+
Trying to get to;
SELECT Column_name(1), Column_name(2)..
From tblServer_Data
There could be up to a total of 20 columns returned.
SQL DEMO
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME([Column_Name])
FROM Table1 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #cols as Columns; -- just for debug
set #query = 'SELECT [ID], ' + #cols + ' from
(
select 1 as ID
, [seqval]
, [Column_Name]
from Table1
) x
pivot
(
max([seqval])
for [Column_Name] in (' + #cols + ')
) p '
SELECT #query as Query; -- just for debug
execute(#query);
OUTPUT
Then you can do SELECT over that output
This will give a SELECT statement of the columns in a selected table.
SELECT 'SELECT ' + STUFF(
(SELECT ',' + c.column_name from
(SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS c
where c.TABLE_NAME = your_table) c
for xml path ('')),1,1,'') + ' FROM ' + your_table
Image transcription:
FTE/RATE CARD | 2018-01-01 | 2018-02-01 | 2018-03-01 | 2018-04-01 | 2018-05-01 | 2018-06-01 | ...
-------------------------------------------------------------------------------------------------
FTE 3 | NULL | NULL | NULL | 33 | 38 | 40.5 | ...
I have a pivot sql query as below.
I need to replace NULL values with Zeros in the result.
I don't know where do I exactly use the IsNull or Coalesce function in the query.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF
(
(
SELECT distinct ',' + QUOTENAME([MONTH])
FROM [HEADCOUNT]
WHERE [MONTH] BETWEEN '01-012018' AND '12-01-2018'
ORDER BY ',' + QUOTENAME([MONTH])
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,''
)
SET #query = 'SELECT [FTE/RATE CARD],' + #cols + ' FROM
(
SELECT [MONTH],[FTE/RATE CARD],[HC]
FROM [HEADCOUNT]
WHERE [CC-LOC] IN ([CC-LOC])
) x pivot (Sum ([HC]) for [MONTH] in (' + #cols + '))p' execute(#query)
You'll need to generate another column list for the select statement, and wrap individual months with ISNULL, like so:
DECLARE #cols AS NVARCHAR(MAX),
#selectCols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #selectCols = STUFF
(
(
SELECT distinct ', ISNULL(' + QUOTENAME([MONTH]) + ', 0) AS ' + QUOTENAME([MONTH])
FROM [HEADCOUNT]
WHERE [MONTH] BETWEEN '01-012018' AND '12-01-2018'
ORDER BY ',' + QUOTENAME([MONTH])
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,''
)
SELECT #cols = STUFF
(
(
SELECT distinct ',' + QUOTENAME([MONTH])
FROM [HEADCOUNT]
WHERE [MONTH] BETWEEN '01-012018' AND '12-01-2018'
ORDER BY ',' + QUOTENAME([MONTH])
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,''
)
SET #query = 'SELECT [FTE/RATE CARD],' + #selectCols + ' FROM
(
SELECT [MONTH],[FTE/RATE CARD],[HC]
FROM [HEADCOUNT]
WHERE [CC-LOC] IN ([CC-LOC])
) x pivot (Sum ([HC]) for [MONTH] in (' + #cols + '))p' execute(#query)
This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 6 years ago.
I'm struggling with an error while making a dynamic pivot table
The source data is
JobID | SalesForMonth | YearMonth
7734 | 400 | 2016-12
7734 | 350 | 2017-01
8540 | 444 | 2016-12
8540 | 300 | 2017-01
and aiming for
JobID | 2016-12 | 2017-01
7734 | 400 | 350
8540 | 444 | 300
and I've tried to use a query I found on here to create the column headers. But must admit I don't really understand the 'For XML' line and getting a syntax error there on line 6
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(YearMonth)
FROM v_JobSalesByMonth
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SELECT #query =
'SELECT * FROM
(SELECT JobID, YearMonth, SalesForMonth
FROM v_JobSalesByMonth) X
PIVOT
(
(JobID, SalesForMonth)
for [YearMonth] in (' + #cols + ')
) P'
I'd also like to stick in a 'total sales' for the jobID column
Any help would be much appreciated
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(YearMonth) From v_JobSalesByMonth Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select [JobID],[TotalSales],' + #SQL + '
From (
Select JobID
,TotalSales = sum(SalesForMonth) over (Partition By JobID)
,YearMonth
,SalesForMonth
From v_JobSalesByMonth A
) A
Pivot (sum(SalesForMonth) For [YearMonth] in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
EDIT - Dynamically Create View
Since you can't have dynamic SQL in a view, you could have job scheduled (daily or monthly) to drop and re-create the view.
if object_id('vw_SalesByMonth','v') is not null
drop view vw_SalesByMonth;
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(YearMonth) From Yourtable Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Create View vw_SalesByMonth
AS
Select [JobID],[TotalSales],' + #SQL + '
From (
Select JobID
,TotalSales = sum(SalesForMonth) over (Partition By JobID)
,YearMonth
,SalesForMonth
From YourTable A
) A
Pivot (sum(SalesForMonth) For [YearMonth] in (' + #SQL + ') ) p'
Exec(#SQL);
Select * from vw_SalesByMonth
I have a table name table1
Partnumber | Model
12345 | A1
12345 | B2
12345 | C3
I would like my output to be:
Partnumber | Model1 | Model2 | Model3
12345 | A1 | B2 | C3
With the model columns N being dynamic.
Any ideas?
You can use dynamic conditional aggregation:
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql =
'SELECT
PartNumber' + CHAR(10) +
STUFF((
SELECT DISTINCT
' ,MAX(CASE WHEN Model = ''' + Model + ''' THEN Model END) AS ' + QUOTENAME(Model) + CHAR(10)
FROM Tbl
FOR XML PATH('')
), 1, 0, '') +
'FROM Tbl
GROUP BY PartNumber;';
PRINT #sql;
EXEC sp_executesql #sql;
Source Table
Col1 |Col2 |Col3 |Col4 | Col5
----------------------------------
hi | this | is | a | test
Destination Table
RowValues|
----------
hi
this
is
a
test
I am using Dynamic SQL.
Any help ?
This is my code , just change table name and the Id in the where clause to what suits you
DECLARE #sql nVARCHAR(max), #TableName nvarchar(100), #where nvarchar(max)
set #TableName = 'stockItems'
set #where= ' where id = 2'
select #sql ='Select '
select #sql = #sql+ + ' '''+ [name] +' = ''+ cast(' + [name] + ' as nvarchar(10)) as '+[name]+', '
from sys.columns where object_name (object_id) = #TableName
set #sql = stuff(#sql, len(#sql), 1, '') + ' From '+#TableName+ #where
print #sql
set #sql = REPLACE(#sql,', From',' From')
set #sql = #sql + ' '
print #sql
exec(#sql)
Now I need to create a new table that has one column that hold holds each value as a row
Thanks to #Mahmoud-Gamal
The solution should be something like below
declare #cols nvarchar(max)
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(column_name)
FROM information_schema.columns
WHERE table_name = 'vehicles'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
declare #statement nvarchar(max)
set #statement ='
SELECT
ColumnName, Value
FROM
Vehicles
UNPIVOT
(
Value
FOR ColumnName
IN
(
'+#cols+'
)
)
AS A'
execute(#statement)
Please change the "vehicle" table name to any table on your database that has columns from different types (datetime, int and nvarchar) and the below error is shown
Any help ?
The type of column "Description" conflicts with the type of other columns specified in the UNPIVOT list.
Use the UNPIVOT table operator:
SELECT col AS RowValues
FROM table1 AS t
UNPIVOT
(
col
FOR value IN([col1],
[col2],
[col3],
[col4],
[col5])
) AS u;
SQL Fiddle Demo
This will give you:
| ROWVALUES |
|-----------|
| hi |
| this |
| is |
| a |
| test |
Update:
In case you don't know the names of the columns, and you want to do this dynamically, you have to do this using dynamic SQL.
But the problem is how to get the columns names?
You can get the columns names from the information_schema.columns, then concatenate them in one sql, then replace the columns' names in the UNPIVOT with this string, and execute that statement dynamically like this:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(column_name)
FROM information_schema.columns
WHERE table_name = 'Table1'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query = ' SELECT col AS RowValues
FROM table1 AS t
UNPIVOT
(
val
FOR col IN ( ' + #cols + ' )
) AS u;';
EXECUTE(#query);
Updated SQL Fiddle Demo
I believe you want this
Select Col1 + Col2 + Col3 + Col4 + Col5 From Table
Or may be following
Select Col1 From Table1
union Select Col2 From Table1
union Select Col3 From Table1
union Select Col4 From Table1
union Select Col5 From Table1 ;