SQL Server Query - How to Pivot this set of data - sql-server

I've been playing around and just not coming up with anything workable :( I have a simple query:
SELECT DISTINCT IP.DeviceUID, IP.DeviceName, d.NodeName from Devices d
inner join IPSCHEMA IP on IP.PLCIP=d.CommunicationAddress
This brings me to the data I want to Pivot (Subset of that data below):
|---------------------|------------------|------------------|
| DeviceUID | DeviceName | NodeName |
|---------------------|------------------|------------------|
| 226 | Boiler | BOILER |
|---------------------|------------------|------------------|
| 226 | Boiler | AMMONIA |
|---------------------|------------------|------------------|
| 226 | Boiler | CHILLER |
|---------------------|------------------|------------------|
| 230 | SSilo | SSUG |
|---------------------|------------------|------------------|
| 230 | SSilo | WALKER |
|---------------------|------------------|------------------|
| 29 | Cooling | AMMONIA |
|---------------------|------------------|------------------|
| 29 | Cooling | BOILER |
|---------------------|------------------|------------------|
| 29 | Cooling | CAR_A |
|---------------------|------------------|------------------|
| 29 | Cooling | CAR_B |
|---------------------|------------------|------------------|
| 29 | Cooling | LINE1 |
|---------------------|------------------|------------------|
I need it to look like the following:
|---------------------|------------------|------------------|------------------|------------------|------------------|------------------|
| DeviceUID | DeviceName | Node1 | Node2 | Node3 | Node 4 | Node5 |
|---------------------|------------------|------------------|------------------|------------------|------------------|------------------|
| 226 | Boiler | BOILER | AMMONIA | CHILLER | | |
|---------------------|------------------|------------------|------------------|------------------|------------------|------------------|
| 230 | SSilo | SSUG | WALKER | | | |
|---------------------|------------------|------------------|------------------|------------------|------------------|------------------|
| 29 | Cooling | AMMONIA | BOILER | CAR_A | CAR_B | LINE1 |
|---------------------|------------------|------------------|------------------|------------------|------------------|------------------|
I'm sure I can export to Excel, modify, make it look like that. But I would like this to be a repeatable Stored Procedure I can use for the current dataset.
Thanks in advance.

Untested, but we just add a PIVOT to your initial query.
This also assumes you have a known or maximum number of nodes. If not, you would have to go DYNAMIC.
Select *
From (
Select *
,Item = concat('Node',Row_Number() over (Partition By DeviceUID,DeviceName Order by (Select null))
From (
SELECT DISTINCT IP.DeviceUID, IP.DeviceName, d.NodeName from Devices d
inner join IPSCHEMA IP on IP.PLCIP=d.CommunicationAddress
) A
) src
Pivot (max(NodeName) for Item in ([Node1],[Node2],[Node3],[Node4],[Node5]) ) pvt

Related

Pivoting a table with multiple columns in SQL

My goal here is to take a list of two corresponding store numbers and provide an output similar to:
Ultimate goal: produce a list of closest stores by travel time and distance based on source data of 2 rows per zip9 where each row is the travel time in distance, and in time, to a store in question.
The result is that each zip code has 2 stores to choose from, and the requirement is being able to return one row with both options.
+-----------+---------------+---------------------+-------------------+-------------------------+
| zip | Shortest_time | Shortest_time_store | Shortest_distance | Shortest_distance_store |
+-----------+---------------+---------------------+-------------------+-------------------------+
| 70011134 | 38.7035 | 75 | 21.3124 | 115 |
| 70011186 | 38.4841 | 75 | 21.4144 | 115 |
| 70011207 | 39.1567 | 75 | 21.1826 | 115 |
| 100013232 | 22.976 | 145 | 9.5031 | 115 |
| 112075140 | 21.888 | 145 | 7.3705 | 115 |
+-----------+---------------+---------------------+-------------------+-------------------------+
Original dataset
+---------------+--------------------------+-----------------------+------------------+
| CORRECTED_ZIP | SourceOrganizationNumber | Travel Time (Minutes) | Distance (Miles) |
+---------------+--------------------------+-----------------------+------------------+
| 70011134 | 75 | 38.7035 | 26.8628 |
| 70011134 | 115 | 39.3969 | 21.3124 |
| 70011186 | 75 | 38.4841 | 26.7609 |
| 70011186 | 115 | 39.6389 | 21.4144 |
| 70011207 | 75 | 39.1567 | 31.2771 |
| 70011207 | 115 | 39.188 | 21.1826 |
| 100013232 | 115 | 28.6561 | 9.50311 |
| 100013232 | 145 | 22.976 | 10.0307 |
| 112075140 | 115 | 36.1803 | 7.37053 |
| 112075140 | 145 | 21.888 | 9.50123 |
+---------------+--------------------------+-----------------------+------------------+
Dataset after I've modified it with this query:
SELECT TOP 1000 [corrected_zip]
, TRY_CONVERT( DECIMAL(18, 4), ROUND([Travel Time (Minutes)], 4)) AS [Unit of Measurement]
, [SourceOrganizationNumber]
, 'Time' AS [Type]
FROM [db].[dbo].[my_table_A] [tt]
WHERE [tt].[CORRECTED_ZIP] IN('070011134', '070011186', '070011207', '112075140', '100013232')
AND [Travel Time (Minutes)] IN
(
SELECT MIN([Travel Time (Minutes)])
FROM [db].[dbo].[my_table_A]
WHERE [CORRECTED_ZIP] = [tt].[CORRECTED_ZIP]
GROUP BY [CORRECTED_ZIP]
)
UNION ALL
SELECT TOP 1000 [corrected_zip]
, TRY_CONVERT( DECIMAL(18, 4), ROUND([Distance (Miles)], 4))
, [SourceOrganizationNumber]
, 'Distance'
FROM [db].[dbo].[my_table_A] [tt]
WHERE [tt].[CORRECTED_ZIP] IN('070011134', '070011186', '070011207', '112075140', '100013232')
AND [Distance (Miles)] IN
(
SELECT MIN([Distance (Miles)])
FROM [db].[dbo].[my_table_A]
WHERE [CORRECTED_ZIP] = [tt].[CORRECTED_ZIP]
GROUP BY [CORRECTED_ZIP]
)
ORDER BY [CORRECTED_ZIP];
+---------------+---------------------+--------------------------+----------+
| corrected_zip | Unit of Measurement | SourceOrganizationNumber | Type |
+---------------+---------------------+--------------------------+----------+
| 70011134 | 38.7035 | 75 | Time |
| 70011134 | 21.3124 | 115 | Distance |
| 70011186 | 21.4144 | 115 | Distance |
| 70011186 | 38.4841 | 75 | Time |
| 70011207 | 39.1567 | 75 | Time |
| 70011207 | 21.1826 | 115 | Distance |
| 100013232 | 9.5031 | 115 | Distance |
| 100013232 | 22.976 | 145 | Time |
| 112075140 | 21.888 | 145 | Time |
| 112075140 | 7.3705 | 115 | Distance |
+---------------+---------------------+--------------------------+----------+
Data after I attempted to pivot it
+---------------+--------------------------+----------+---------+
| corrected_zip | SourceOrganizationNumber | Distance | Time |
+---------------+--------------------------+----------+---------+
| 070011134 | 115 | 21.3124 | NULL |
| 070011134 | 75 | NULL | 38.7035 |
| 070011186 | 115 | 21.4144 | NULL |
| 070011186 | 75 | NULL | 38.4841 |
| 070011207 | 115 | 21.1826 | NULL |
| 070011207 | 75 | NULL | 39.1567 |
| 100013232 | 115 | 9.5031 | NULL |
| 100013232 | 145 | NULL | 22.9760 |
| 112075140 | 115 | 7.3705 | NULL |
| 112075140 | 145 | NULL | 21.8880 |
+---------------+--------------------------+----------+---------+
It seems like my issue is picking the correct store ID as opposed to grouping by store ID?
You can use row_number() twice in a subquery(once to rank by time, another by distance), and then do conditional aggregation in the outer query:
select
corrected_zip,
min(travel_time) shortest_time,
min(case when rnt = 1 then source_organization_number end) shortest_time_store,
min(distance) shortest_distance,
min(case when rnd = 1 then source_organization_number end) shortest_distance_store
from (
select
t.*,
row_number() over(partition by corrected_zip order by travel_time) rnt,
row_number() over(partition by corrected_zip order by distance) rnd
from mytable t
) t
group by corrected_zip

Sum in subquery for a group of numbers

We are trying to get a combined table where we also try to sum the volume.
Dateset right now:
+-------------+-----+------------+------------+--------+---------+
| Voorziening | BSN | Begindatum | Einddatum | Volume | Product |
+-------------+-----+------------+------------+--------+---------+
| 1000 | 1 | 1-1-2017 | 31-1-2017 | 50 | AAAA |
+-------------+-----+------------+------------+--------+---------+
| 1200 | 1 | 1-2-2017 | 31-3-2017 | 200 | AAAA |
+-------------+-----+------------+------------+--------+---------+
| 1250 | 1 | 1-4-2017 | 10-4-2017 | 90 | AAAA |
+-------------+-----+------------+------------+--------+---------+
| 1111 | 2 | 4-1-2017 | 10-1-2017 | 4 | AABB |
+-------------+-----+------------+------------+--------+---------+
| 1345 | 2 | 11-1-2017 | 29-1-2017 | 80 | AABB |
+-------------+-----+------------+------------+--------+---------+
| 2000 | 1 | 10-1-2017 | 31-1-2017 | 90 | CCCC |
+-------------+-----+------------+------------+--------+---------+
| 2190 | 1 | 1-2-2017 | 31-12-2017 | 100 | CCCC |
+-------------+-----+------------+------------+--------+---------+
What I want to achieve
+-------------+-----+------------+------------+--------+---------+
| Voorziening | BSN | Begindatum | Einddatum | Volume | Product |
+-------------+-----+------------+------------+--------+---------+
| 1000 | 1 | 1-1-2017 | 10-4-2017 | 340 | AAAA |
+-------------+-----+------------+------------+--------+---------+
| 2000 | 1 | 10-1-2017 | 31-12-2017 | 190 | CCCC |
+-------------+-----+------------+------------+--------+---------+
| 1111 | 2 | 4-1-2017 | 29-1-2017 | 84 | AABB |
+-------------+-----+------------+------------+--------+---------+
What i've got so for is the folowwing query:
SELECT min(b.Voorziening) as voorzieningsnummer
,a.BSN
,min(b.Begindatum) as mindatum
,MAX(b.Einddatum) AS maxdatum
,a.Productcode
,
(SELECT sum(Volume)
FROM Voorziening
)as totaal
FROM Voorziening a
INNER JOIN Voorziening b
ON a.BSN = b.BSN
AND a.Productcode = b.Productcode
GROUP BY a.BSN, a.Productcode
The result is gives me is this:
+-------------+-----+------------+------------+--------+
| Voorziening | BSN | Begindatum | Einddatum | Volume |
+-------------+-----+------------+------------+--------+
| 1000 | 1 | 1-1-2017 | 10-4-2017 | 424 |
+-------------+-----+------------+------------+--------+
| 1111 | 2 | 4-1-2017 | 29-1-2017 | 424 |
+-------------+-----+------------+------------+--------+
You guys can help me to get the sum right?
There isn't any reason to use JOIN. you can use aggregate function directly.
You can try this.
SELECT min(a.Voorziening) as voorzieningsnummer
,a.BSN
,min(a.Begindatum) as mindatum
,MAX(a.Einddatum) AS maxdatum
,a.Productcode
,SUM(a.Volume) Volume
FROM Voorziening a
GROUP BY a.BSN, a.Productcode
if you are using sql server 2008 or above version then just go ahead with PARTITION BY
SUM(Volume)over(Partition by Product order by Voorziening,another,another)

SQL Server How to Utilize Pivot in this difficult situation

I've been reading a lot of posts on here trying to figure out how to use this pivot function and have not had any luck. Either some of the explanations included something unnecessary to me or made it too difficult for to understand because I only recently started teaching myself SQL.
I need to figure out how to Group my dates into one if possible and turn P1, P2, P3... into columns. Making P1-10 into their each individual column is what is most important.
This is what the original SQL Server looks like.. + many other columns that are irrelevant for what I'm trying to do.
+-------------+------------+---------------------+
| StationName | Start_Time | Time |
+-------------+------------+---------------------+
| P1 | 15 | 2018-06-21 13:37:34 |
+-------------+------------+---------------------+
| P3 | 69 | 2018-06-21 12:33:55 |
+-------------+------------+---------------------+
| P4 | 52 | 2018-06-21 13:42:34 |
+-------------+------------+---------------------+
| P1 | 18 | 2018-06-21 10:37:34 |
+-------------+------------+---------------------+
| P9 | 78 | 2018-06-21 6:37:34 |
+-------------+------------+---------------------+
This is what I currently have
SELECT Cast(Start_Time AS DATE) AS Date,
StationName,
sum(time) AS "Daily Downtime"
FROM A6K_Events
Where StationName Like 'P%'
GROUP BY Cast(Start_Time AS DATE), StationName
Order By Date DESC
+------------+-------------+----------------+
| Date | StationName | Daily Downtime |
+------------+-------------+----------------+
| 2018-06-21 | P1 | 33 |
+------------+-------------+----------------+
| 2018-06-21 | P3 | 62 |
+------------+-------------+----------------+
| 2018-06-21 | P8 | 1 |
+------------+-------------+----------------+
| 2018-06-21 | P9 | 78 |
+------------+-------------+----------------+
| 2018-06-20 | P1 | 69 |
+------------+-------------+----------------+
| 2018-06-19 | P1 | 52 |
+------------+-------------+----------------+
This is what I would like to have:
+------------+----+----+----+----+----+----+----+----+----+-----+
| Date | P1 | P2 | P3 | P4 | P5 | P6 | P7 | P8 | P9 | P10 |
+------------+----+----+----+----+----+----+----+----+----+-----+
| 2018-06-21 | 33 | | 62 | | | | | 1 | 78 | |
+------------+----+----+----+----+----+----+----+----+----+-----+
| 2018-06-20 | 69 | | | | | | | | | |
+------------+----+----+----+----+----+----+----+----+----+-----+
| 2018-06-19 | 52 | | | | | | | | | |
+------------+----+----+----+----+----+----+----+----+----+-----+
The Numbers filled in would be the Daily Downtime value for that process that day. The end result will be recorded live and contain many dates and various down times.
Thanks for the Help in advance
Edited to add text tables and removed images
You can accomplish the output with the following pivot statement.
SELECT * FROM(
SELECT CAST([Start_Date] AS DATE) as [DATE],SUM(TIME) AS [Daily DownTime],STATIONNAME FROM A6K_Events Where StationName Like 'P%' GROUP BY [start_date],STATIONNAME
) AS S
PIVOT(sum([Daily DownTime]) FOR STATIONNAME IN([P1],[P2],[P3],[P4],[P5],[P6],[P7],[P8],[P9],[P10])) AS PT
http://rextester.com/BAXY34111

Reducing rows based on a grouped MAX()

Scratching my head for a day on this.
Need to reduce a list of films and genres to a list of films and genres based on the grouped max() views associated with the film.
So transforming 'a' to 'b' here with T-SQL
(Purple rows are the valid ones that will make it output table: Image )
+---------+--------------+-------+
| Title | Genre | Views |
+---------+--------------+-------+
| Mad Max | Mockumentary | 1 |
| Mad Max | Sci-fi | 169 |
| Mad Max | Documentary | 32 |
| Titanic | Drama | 6 |
| E.T. | Sci-fi | 34 |
| E.T. | Sci-fi | 2 |
| E.T. | Horror | 1 |
| Taken | Triller | 60 |
| Taken | Crime Drama | 2 |
| Taken | Triller | 40 |
| Taken | Crime Drama | 15 |
+---------+--------------+-------+
Expected outcome
+---------+---------+-------+
| Title | Genre | Views |
+---------+---------+-------+
| Mad Max | Sci-fi | 169 |
| Titanic | Drama | 6 |
| E.T. | Sci-fi | 36 |
| Taken | Triller | 100 |
+---------+---------+-------+
Try this one...
SELECT title, genre, views
FROM (SELECT title,
genre,
Sum(views) AS views,
ROW_NUMBER() OVER (PARTITION BY title ORDER BY Sum(views) DESC) AS ranks
FROM tablename
GROUP BY title, genre) tmp
WHERE ranks < 2
Output
+---------+---------+-------+
| title | genre | views |
+---------+---------+-------+
| E.T. | Sci-fi | 36 |
| Mad Max | Sci-fi | 169 |
| Taken | Triller | 100 |
| Titanic | Drama | 6 |
+---------+---------+-------+
Online Demo: http://www.sqlfiddle.com/#!18/e34fe/1/0

Optimisation of a MSSQL Query - group by multiple columns

Hey guys i could need some advice, i've the following 2 tables
Table Model:
+----------------+---------------+-------------+------------------------+-------------+--------+-----------------+------------------+------------------+------------------------------+------------------------------+----------------------+----------------------+------------------+
| DLTCountryCode | SupplierID | ModelNumber | ModelDescription | Brand | Fedas | MeasurementUnit | MinModelNetPrice | MaxModelNetPrice | MinModelSuggestedRetailPrice | MaxModelSuggestedRetailPrice | MinModelInsteadPrice | MaxModelInsteadPrice | PictureAvailable |
+----------------+---------------+-------------+------------------------+-------------+--------+-----------------+------------------+------------------+------------------------------+------------------------------+----------------------+----------------------+------------------+
| AT | 9120048150008 | 2012266 | xxx | Brand | 115946 | STK | 6.05 | 6.05 | 10.95 | 10.95 | 0 | 0 | 1 |
+----------------+---------------+-------------+------------------------+-------------+--------+-----------------+------------------+------------------+------------------------------+------------------------------+----------------------+----------------------+------------------+
Table ModelColorSizeInventory:
+----------------+---------------+-------------+-----------+------+---------------+----------+-------------------------+
| DLTCountryCode | SupplierID | ModelNumber | ColorCode | Size | ItemNumber | Quantity | InventoryDateTime |
+----------------+---------------+-------------+-----------+------+---------------+----------+-------------------------+
| AT | 9120048150008 | 2012266 | 801 | L | 9008601584968 | 0 | 2017-09-29 11:16:02.347 |
| AT | 9120048150008 | 2012266 | 801 | M | 9008601584951 | 0 | 2017-09-29 11:16:02.347 |
| AT | 9120048150008 | 2012266 | 801 | S | 9008601584944 | 2 | 2017-09-29 11:16:02.347 |
| AT | 9120048150008 | 2012266 | 801 | XL | 9008601584975 | 4 | 2017-09-29 11:16:02.347 |
| AT | 9120048150008 | 2012266 | 801 | XXL | 9008601584982 | 6 | 2017-09-29 11:16:02.347 |
+----------------+---------------+-------------+-----------+------+---------------+----------+-------------------------+
And the following Query:
SELECT dccdm.*, SUM(dccdmcsi.[Quantity]) AS QuantityModel
FROM "Model" AS "dccdm"
LEFT JOIN ModelColorSizeInventory AS dccdmcsi ON dccdm.[ModelNumber] = dccdmcsi.[ModelNumber]
WHERE (
dccdm.ModelNumber IN('2012266')
)
AND dccdmcsi.[Quantity] >0
AND dccdm.[DLTCountryCode]='AT'
GROUP BY dccdm.[DLTCountryCode],dccdm.[SupplierID],dccdm.[ModelNumber],dccdm.[ModelDescription],dccdm.[Brand],dccdm.[Fedas],dccdm.[MeasurementUnit],dccdm.[MinModelNetPrice],dccdm.[MaxModelNetPrice],dccdm.[MinModelSuggestedRetailPrice],dccdm.[MaxModelSuggestedRetailPrice],dccdm.[MinModelInsteadPrice],dccdm.[MaxModelInsteadPrice],dccdm.[PictureAvailable]
This Query works as expected, i'm joining ModelColorSizeInventory to find out the sum of all variants with quantities
One thing that bothers me is the group by part, because if i skip the group by statement i'm getting the following error:
Msg 8120, Column 'DLTCountryCode' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Since i'm not that familiar with MSSQL i ask the following question:
How can i write down this query without using this complex GROUP BY clause
The reason behind this question is that writing down multiple columns in a group by statement feels wrong, in queries like these ... ;)
You could use "subview" for grouped amounts, or simply use subquery in join, like:
Select dccdm.*, Isnull(dccdmcsi.SumQuantity,0)
FROM dbo.[Model] dccdm LEFT JOIN
(Select ModelNumber, SUM([Quantity]) as SumQuantity from dbo.ModelColorSizeInventory GROUP BY ModelNumber) dccdmcsi
ON dccdm.ModelNumber=dccdmcsi.ModelNumber

Resources