SQL Server Query for Many to Many Relationship - how to query? - sql

This is an update to my previous question : Many to many relationship
The previous solution works fine, but now I want tgo improve the results a little bit. I´d like to have all the wavelength values in one row.
So instead of the following result :
DateTimeID Wavelength SensorID
11435 1581,665 334
11435 1515,166 334
11435 1518,286 335
I'd like to have something similar to this:
DateTimeID Wavelength1 Wavelength2 SensorID
11435 1581,665 1515,166 334
11435 1518,286 335

You could use the following which applies a row_number() to the records:
select DateTimeID,
[1] as Wavelength1,
[2] as Wavelength2,
SensorId
from
(
select [DateTimeID], [Wavelength], [SensorID],
row_number() over(partition by DateTimeID, SensorId
order by DateTimeID) rn
from yourtable
) src
pivot
(
max(Wavelength)
for rn in ([1], [2])
) piv
See SQL Fiddle with Demo.
If you will have an unknown number of wavelength values, then you can use dynamic SQL to generate this:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME('Wavelength'+cast(rn as varchar(50)))
from
(
select row_number() over(partition by DateTimeID, SensorId
order by DateTimeID) rn
from yourtable
) src
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT DateTimeID,' + #cols + ', SensorId from
(
select [DateTimeID], [Wavelength], [SensorID],
''Wavelength''+cast(row_number() over(partition by DateTimeID, SensorId
order by DateTimeID) as varchar(50)) rn
from yourtable
) x
pivot
(
max(Wavelength)
for rn in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo

Related

How to create dynamic pivot query in SQL

I am trying to create dynamic pivot query in SQL but my issue is that the contract id and the tier desc columns are both dynamic and I could not figure out how to solve this issue. I have something like this:
and this is the output I would like to see
This can be done with repeating column names, however, I can't imagine why one would want this.
The #Col is where we apply the Alias ...[#] as [Tier Value]...
Example
Declare #Col varchar(max) = Stuff((Select Distinct ',' + concat(QuoteName(row_number() over (Partition By ContractID Order by TierDesc)),' as [Tier Value]') From Yourtable Order by 1 For XML Path('')),1,1,'')
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(row_number() over (Partition By ContractID Order by TierDesc)) From Yourtable Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select ContractID,'+#Col+'
From (
Select ContractID
,TierDesc
,ColNr = row_number() over (Partition By ContractID Order by TierDesc)
From YourTable
) Src
Pivot (max(TierDesc) for ColNr in ('+#SQL+') ) pvt
'
Exec(#SQL)
Returns
ContractID Tier Value Tier Value Tier Value
123 tier1 tier2 NULL
555 tier4 tier5 tier6
652 tier0 tier4 NULL
EDIT - Then generated SQL Looks like this
Select ContractID
,[1] as [Tier Value]
,[2] as [Tier Value]
,[3] as [Tier Value]
From (
Select ContractID
,TierDesc
,ColNr = row_number() over (Partition By ContractID Order by TierDesc)
From YourTable
) Src
Pivot (max(TierDesc) for ColNr in ([1],[2],[3]) ) pvt
EDIT 2
Select Distinct
ColNr = row_number() over (partition by ContractID Order By TierDesc)
From Yourtable

Adding a WHERE statement refering another table in Dynamic SQL

I currently have the following script which is pivoting results from rows into columns. It works a Great, apart from two issues;
I have a flag in another table which I want to filter by (basically: WHERE Table.Stats=YES). I'd normally do this in a basic query with an inner join followed by that WHERE statement. In the query below, I already have a WHERE FileSeq=25, which works, but this criteria I need to get working is calling on a different table.
The query is returning a lot of uncessary NULL fields.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(col+CAST(rn AS varchar(6)))
FROM
(
SELECT row_number() over(partition by UID ORDER BY ClassCode) rn
FROM dbo.StudentClasses
) d
CROSS APPLY
(
SELECT 'ClassCode', 1
) c (col, so)
GROUP BY col, rn, so
ORDER BY rn, so
FOR XML PATH(''), TYPE
).VALUE('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT UID,' + #cols + '
FROM
(
SELECT UID, col+CAST(rn AS varchar(10)) col, VALUE
FROM
(
SELECT UID, classcode,
row_number() over(partition by UID ORDER BY classcode) rn
FROM StudentClasses WHERE FileSeq=25
) t
CROSS APPLY
(
SELECT ''classcode'', CAST(classcode AS varchar(6))
) c (col, VALUE)
) x
PIVOT
(
MAX(VALUE)
for col in (' + #cols + ')
) p '
EXECUTE(#query)
Any assistance appreciated

SQL Server Sort fixed number of rows/columns horizontally

I'm trying use PIVOT in a SQL Server stored procedure to take the following data:
ID Rank
203081 1.1
200761 3.9
202687 5.3
203135 5.0
203090 3.3
and return the ID's sorted horizontally. The ranking goes from 1 to 6 with each rank having tenths in between. Example 1.0, 1.1, 1.2, 1.3, ... 1.9, 2.0
The ID's need to be sorted in order by rank.
The result should return something like the following:
(if additional columns needed for aggregation that is fine as well.)
[1] ,[2] ,[3] ,[4] ,[5]
202687,203135,200761,203090,203081
Using above data the ID's would be sorted by rank as 5.3->5.0->3.9->3.3->1.1
In the end I need to take the results and insert them into another table with the ID's sorted horizontally.
I can't get the PIVOT to work correctly. I'm sure it is something obvious I'm not seeing.
If there is a better/faster way to achieve what is needed I would like to know what that solution would be as well.
It sounds like you just need to use row_number() to get the ordering correct and then PIVOT the data on that row number.
If you have a limited number values then you can use:
select [1], [2], [3], [4], [5]
from
(
select id,
row_number() over(order by [rank] desc) seq
from yourtable
) d
pivot
(
max(id)
for seq in ([1], [2], [3], [4], [5])
) piv;
See SQL Fiddle with Demo
Or if you are going to have an unknown number, you will use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(row_number() over(order by [rank] desc))
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #cols + '
from
(
select id,
row_number() over(order by [rank] desc) seq
from yourtable
) x
pivot
(
max(id)
for seq in (' + #cols + ')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo. These give a result:
| 1 | 2 | 3 | 4 | 5 |
|--------|--------|--------|--------|--------|
| 202687 | 203135 | 200761 | 203090 | 203081 |

SQL rotate rows to columns...dynamic number of rows [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
SQL Server dynamic PIVOT query?
I have a dataset that has the below structure.
CREATE TABLE #TempTable
(
Measure_ID INT,
measurement DECIMAL(18, 4)
)
INSERT INTO #TempTable
VALUES
(1,2.3)
,(1,3.4)
,(1,3.3)
,(2,3)
,(2,2.3)
,(2,4.0)
,(2,4.5)
I need to produce output that will look like this.
1,2.3,3.4,3.3
2,3,2.3,4.0,4.5
Basically its a pivot on Measure_ID. Unfortunately, there can be an unlimited number of measure_id's. So Pivot is out.
I'm hoping to avoid CURSORS, but will if that turns out to be the best approach.
If you have an unknown number of values, then you can use a PIVOT with dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ','
+ QUOTENAME('Measurement_' + cast(rn as varchar(10)))
from temptable
cross apply
(
select row_number() over(partition by measure_id order by measurement) rn
from temptable
) x
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT measure_id, ' + #cols + ' from
(
select measure_id, measurement,
''Measurement_''
+ cast(row_number() over(partition by measure_id order by measurement) as varchar(10)) val
from temptable
) x
pivot
(
max(measurement)
for val in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle With Demo
If you have a known number of values, then you can hard-code the values, similar to this:
SELECT measure_id, [Measurement_1], [Measurement_2],
[Measurement_3], [Measurement_4]
from
(
select measure_id, measurement,
'Measurement_'
+ cast(row_number() over(partition by measure_id order by measurement) as varchar(10)) val
from temptable
) x
pivot
(
max(measurement)
for val in ([Measurement_1], [Measurement_2],
[Measurement_3], [Measurement_4])
) p
See SQL Fiddle With Demo
Both queries will produce the same results:
MEASURE_ID | MEASUREMENT_1 | MEASUREMENT_2 | MEASUREMENT_3 | MEASUREMENT_4
==========================================================================
1 | 2.3 | 3.3 | 3.4 | (null)
2 | 2.3 | 3 | 4 | 4.5

Dynamic pivot table with two id columns

This is probably simple but I"m just not seeing it. Your help is appreciated. I have a table in MS SQLServer that looks like this
CustomerID Time ItemID
1 2008-10-07 06:32:53:00.000 87432
1 2008-10-07 06:32:53:00.000 26413
2 2010-06-23 03:45:10:00.000 6312
2 2011-09-14 07:36:03:00.000 87432
2 2011-09-14 07:36:03:00.000 87432
I want to end up with a table that has each customer, the timestamp and the count of the items purchased during that timestamp, that looks like this
CustomerID Time 87432 26413 6312
1 2008-10-07 06:32:53:00.000 1 1 0
2 2010-06-23 03:45:10:00.000 0 0 1
2 2011-09-14 07:36:03:00.000 2 0 0
In the source table, the time and itemID are variable (and plentiful), so I'm thinking a dynamic pivot will do the trick. Is this possible to do with pivot? If so, how?
You can do this with a dynamic PIVOT. This will count the number of ItemIds that you have for any number of Times.
See a SQL Fiddle with a Demo. This demo leaves the time as a varchar as you stated they were. But this will work if the data is a datetime as well.
Since you want time in the final result, then when you select the columns, you will need to add the time column twice. I called it time1 and time. This allows you to aggregate on time1 in the PIVOT and still have a time column for your final product.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(itemid)
from temp
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT customerid, [time], ' + #cols + ' from
(
select customerid, [time] as time1, [time] as [time], itemid
from temp
) x
pivot
(
count([time1])
for itemid in (' + #cols + ')
) p '
execute(#query)
Approach #1 - Click here to see Demo
Declare #ItemIDs varchar(1000) = ''
Declare #Query varchar(8000) = ''
Select #ItemIDs = ISNULL(QuoteName(Convert(varchar, ItemID)) + ',', '')
+ #ItemIDs
From
(
Select distinct ItemID From #MyTable
)K
SET #ItemIDs = SUBSTRING(#ItemIDs,0,len(#ItemIDs))
SET #Query = 'Select CustomerID, [Time],' +
#ItemIDs + ' From
(
Select CustomerID, [Time], ItemID from #MyTable
)K Pivot
(
count(ItemID) FOR ItemID IN (' + #ItemIDs + ')
) AS pvt'
EXEC(#Query)
Approach #2 - Click here to see Demo
Select CustomerID, [Time], [87432] as [87432],
[26413] as [26413], [6312] as [6312] From
(
Select CustomerID, [Time], ItemID from #MyTable
)K Pivot
(
count(ItemID) FOR ItemID IN ([87432] , [26413],[6312])
) AS pvt