Self referencing dynamic SQL pivot query returning unwanted results - sql

I know there are better ways to design the table but this is just an example of what I need
I just can't seem to get the results I'm looking for
Table and data:
Query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(columnType)
FROM [Values]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = 'SELECT ' + #cols + ' FROM
(
SELECT value, columnType
FROM [Values]
) x
PIVOT
(
MAX(value)
FOR columnType IN (' + #cols + ')
) p '
EXECUTE(#query)
Result I get:
Results I want
Product Item SubItem
A A A A A A
A A B A A B
B B A NULL

Your query can be easily resolved using joins for two levels:
select v.value as Product, vi.value as Item, vsi.value as Subitem
from [Values] v left join
[Values] vi
on vi.column_type = 'Item' and vi.parent_id = v.id left join
[Values] vsi
on vsi.column_type = 'Sub Item' and vsi.parent_id = v.id
where v.column_type = 'Product';
If you have an unknown number of levels, then you can expand on this query using dynamic SQL.

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

Reverse Table In SQL

I have query:
SELECT DISTINCT temp.ID,request.RequestTypeID
FROM #MyTempTable6 as temp
JOIN dbo.FingerMachineUsers as fingeruser
ON temp.UserNo = fingeruser.ID
JOIN dbo.AppUsers as appuser
ON appuser.Id = fingeruser.UserId
LEFT JOIN dbo.Requests as request
ON request.UserId = fingeruser.UserId
And result of it:
How can I create table like this:
ID|RequestTypeID1|RequestTypeID2
1 | 4| 5
If you have only two values, then the simplest method is aggregation:
SELECT t.ID, MIN(r.RequestTypeID), MAX(r.RequestTypeID)
FROM #MyTempTable6 t JOIN
dbo.FingerMachineUsers fu
ON t.UserNo = fu.ID JOIN
dbo.AppUsers au
ON au.Id = fu.UserId LEFT JOIN
dbo.Requests r
ON r.UserId = fu.UserId
GROUP BY t.ID;
If you have have a variable number of values that you want to present, then the query is much more complicated.
PIVOT operator could be your best friend, if there are always only 2 values each...
Try this query...
Disclaimer: This code is purely based on this answer. (https://stackoverflow.com/a/10404455/6327676)
DECLARE #cols AS NVARCHAR(max),
#query AS NVARCHAR(max);
SET #cols = Stuff((SELECT DISTINCT ',' + Quotename(stff.requesttypeid)
FROM TableName stff
FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, ''
)
SET #query = 'SELECT ID, '+ #cols
+ ' FROM (select ID, RequestTypeId FROM TableName) x pivot (MAX(RequestTypeId) FOR RequestTypeId in ('
+ #cols + ')) p'
EXECUTE(#query)
Try this code it will work according to the result you want.
Firstly you need to dump #MyTempTable6 table into #temptable
then set RequestTypeID columns as comma seperated in #colums varible then set the columnname in #Requestcolumns variable,Then use pivot.
DECLARE #colums AS NVARCHAR(max)
DECLARE #Requestcolumns AS NVARCHAR(max)
DECLARE #query AS NVARCHAR(max);
SELECT DISTINCT temp.ID,request.RequestTypeID
into #temptable
FROM #MyTempTable6 as temp
JOIN dbo.FingerMachineUsers as fingeruser
ON temp.UserNo = fingeruser.ID
JOIN dbo.AppUsers as appuser
ON appuser.Id = fingeruser.UserId
LEFT JOIN dbo.Requests as request
ON request.UserId = fingeruser.UserId
SET #colums = Stuff((SELECT DISTINCT ',' +Quotename(tab.RequestTypeID)
FROM #temptable tab
FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, ''
)
SET #Requestcolumns = Stuff((SELECT DISTINCT ',' +Quotename(tab.RequestTypeID) +' AS ',+Quotename('RequestTypeID'+CONVERT(varchar(100),tab.RequestTypeID))
FROM #temptable tab
FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, ''
)
SET #query = 'SELECT ID, '+#Requestcolumns
+ ' FROM (select ID, RequestTypeID FROM #temptable) x pivot (MAX(RequestTypeID) FOR RequestTypeID in ('
+ #colums + ')) p'
EXECUTE(#query)
DROP table #temptable

Dynamic SQL Pivot Causing Duplicate Columns

I created a Dynamic SQL query which joins a few tables, and then pivots off a table called Geometries which stores Name/Value pairs. The SQL is dynamic, because at run-time I won't know which name/value pairs are required to pivot off of.
The query below gets me the data I need, however, all of the geometry columns are listed twice as if I pivoted twice off the same data. I cannot figure out why this happening. I suspect it has to do with the fact that I select the Name/Value pairs in my common table expression which selects the Geometry Name/Value columns on line 13 of the code sample below: g.Name[Geometry], g.Value
Maybe coupling that with the PIVOT code near the bottom is causing the duplicate column data in my query results?
I can't remove the code on line 13, or the PIVOT fails with errors saying Geometry and Value are not valid column names.
Anyway, here is the query...
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT distinct ',' + QUOTENAME(g.Name)
FROM Geometries g
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query =
'SELECT *, ' + #cols + '
FROM (
SELECT
r.Id[RunId], rd.Id[RunDataId], r.RunNumber [Run #], r.TestNumber [Test #], r.Description,
rd.data1, rd.data2, rd.data3,
g.Name[Geometry], g.Value
FROM dbo.Runs r
INNER JOIN RunDatas rd ON r.Id = rd.RunId
INNER JOIN RunGeometries rg ON rg.RunId = r.Id
INNER JOIN Geometries g ON g.Id = rg.GeometryId
) as data
PIVOT
(
Max(Value) FOR Geometry IN (' + #cols + ')
) as p'
execute sp_executesql #query
Any help figuring out what is causing the duplicate data would be appreciated.
select * is including the columns you are pivoting; try this:
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT distinct ',' + QUOTENAME(g.Name)
FROM Geometries g
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query =
'SELECT [RunId], [RunDataId], [Run #], [Test #], Description, data1, data2, data3, ' + #cols + '
FROM (
SELECT
r.Id as [RunId], rd.Id as [RunDataId], r.RunNumber as [Run #], r.TestNumber as [Test #], r.Description,
rd.data1, rd.data2, rd.data3,
g.Name[Geometry], g.Value
FROM dbo.Runs r
INNER JOIN RunDatas rd ON r.Id = rd.RunId
INNER JOIN RunGeometries rg ON rg.RunId = r.Id
INNER JOIN Geometries g ON g.Id = rg.GeometryId
) as data
PIVOT
(
Max(Value) FOR Geometry IN (' + #cols + ')
) as p'
print #query -- you can also take a look at the code you are generating to help troublshoot
execute sp_executesql #query
You can also check the code that is being generated with print #query or select #query.

The column '638' was specified multiple times for 'PVT'. Pivot

I've the following SQL Query
Select Product_Id, [riy] AS [riy],
[eas] AS [eas]
FROM
(SELECT Product_Id, Store_Name, Quantity
FROM [Product_Stock] INNER JOIN Store on Store.Id = [Product_Stock].Stock_Id where Product_Id = 435) ps
PIVOT
(
SUM(Quantity)
FOR Store_Name IN
([riy],[EAST WAREHOUSE - eas])
) AS pvt
it gives the expected result.Giving me total quantity for locations riy and eas.
However, I want to dynamically get the Store names instead of manually specifying them.
this is what I've done.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME([Product_Id])
FROM [Product_Stock]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #query =
'SELECT Product_Id FROM
(SELECT Product_Id, Store_Name, Quantity
FROM [Product_Stock] INNER JOIN Store on Store.Id = [Product_Stock].Stock_Id where Product_Id = 435) PS
PIVOT
(
SUM(Quantity)
FOR Store_Name in (' + #cols + ')
) AS PVT'
EXEC SP_EXECUTESQL #query
This gives me an error saying The column '638' was specified multiple times for 'PVT'.
How can i solve this problem?
Without knowing your actual data this is a blind flight, but I think you have two issues:
You must use DISTINCT to get each value only once
You are not concatenating the stores names but the IDs of your products
Try this
SELECT #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME([Store_Name])
FROM [Product_Stock]
INNER JOIN Store on Store.Id = [Product_Stock].Stock_Id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
Just make sure the cols are DISTINCT
... STUFF((SELECT DISTINCT ','...
Thanks #Shnugo for pushing me in the right direction. Here's the query I finally ended up using.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME([Store].Store_Name)
FROM [Store] INNER JOIN Product_Stock ON Product_Stock.Stock_Id = Store.Id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #query =
'SELECT Product_Id , ' + #cols + ' from
(SELECT Product_Id, Store_Name, Quantity
FROM [Product_Stock] INNER JOIN Store on Store.Id = [Product_Stock].Stock_Id WHERE Product_Stock.product_id = 435 ) PS
PIVOT
(
SUM(Quantity)
FOR Store_Name in (' + #cols + ')
) AS PVT'
EXEC SP_EXECUTESQL #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