TSQL - Convert Rows per record to Columns

浪子不回头ぞ 提交于 2021-01-28 07:36:42

问题


Consider the following table:

+------------------------------------------------------------------------------+
| GUID   | DeviceGUID | DetailGUID | sValue  | iValue  | gValue  | DateStored  |
| ENTRY1 | DEVICE1    | Detail1    | SN112   |         |         | 01/01/2020  |
| ENTRY2 | DEVICE1    | Detail4    |         | 1241    |         | 01/01/2020  |
| ENTRY3 | DEVICE1    | Detail7    |         |         | GUID12  | 01/01/2020  |
| ENTRY4 | DEVICE2    | Detail1    | SN111   |         |         | 01/01/2020  |
| ENTRY5 | DEVICE2    | Detail2    | RND123  |         |         | 01/01/2020  |
| ENRTY6 | DEVICE2    | Detail4    |         | 2351    |         | 03/01/2020  |
| ENTRY7 | DEVICE3    | Detail1    | SN100   |         |         | 02/01/2020  |
| [...]  | [...]      | [...]      |         |         |         |             |
|        |            |            |         |         |         |             |
+------------------------------------------------------------------------------+

I have a table which links a DeviceGUID with a DetailsGUID, with the idea of having unlimited options for Details (just create a new detail and it will be fetchable). however, this means I have a finite and unknown amount of records per deviceGUID.

What I want to show to my users is a table like this:


+--------+---------------------------------------------------------------------+
| GUID   | DeviceGUID |Detail1 |Detail2 |Detail4 |Detail7 |DateStored          |
| ENTRY1 | DEVICE1    |SN112   | [NULL] |1241    |GUID12  | [MAX DateStored]   |
| ENTRY2 | DEVICE2    |SN111   | RND123 |2351    | [NULL] | [MAX DateStored]   |
| ENTRY3 | DEVICE3    |SN100   |        |        |        |                    |
| [...]  | [...]      |        |        |        |        |                    |
+------------------------------------------------------------------------------+

I have been searching a bit and found the PIVOT option but that only seems to function for one field, another option was CROSS APPLY, but that (seems to) need to convert everything to the same datatype; as I hope is visible n the ColumnNames, I will have 3 types of data: String (VARCHAR) value, Integer value, GUID (uniqueidentifier) value, and they will not be interchangeable (meaning Detail with GUID Detail1 will always have a VARCHAR, Detail with DetailGUID Detail4 will always be an Integer

what I was able to find out until now:

DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns+=N', p.'+QUOTENAME([Name])
FROM
(
    SELECT GUID AS [Name]
    FROM [dbo].Details AS p
) AS x;

SET @sql = N'
SELECT [DeviceObjectGUID], '+STUFF(@columns, 1, 2, '')+' FROM (
SELECT [DeviceObjectGUID], [DateStored], [DetailGUID] as [Name] 
    FROM [dbo].[DeviceDetails]) AS j PIVOT (MAX(DateStored) FOR [Name] in 
       ('+STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '')+')) AS p;';
EXEC sp_executesql @sql

to make a dynamic PIVOT for transposing the data.. but as mentioned this is limited to one column

and

select DeviceObjectGUID, value
from DeviceDetails
cross apply
(
  select 'sValue', cast(sValue as varchar(MAX)) union all
  select 'gValue', cast(gValue as varchar(MAX))union all
  select 'iValue', cast(iValue as varchar(MAX))
) c(col, value)

This will have me converting all fields to VARCHAR..

One other option I tried (to understand PIVOT) was this:

SELECT *
FROM
(SELECT *
    FROM [dbo].[DeviceDetails]
) AS SourceTable 
    PIVOT(
    max(sValue)FOR [DetailGUID] IN(
        [450533BB-43B2-499B-B2F7-094BFAE949B0],
        [7483E518-EB61-4B72-93F7-0F97BBFAFA01],
        [29B1BDE8-3AD4-4576-8B76-3CAE83E10B11],
        [5FC8CC76-12EB-4924-9320-5D09BBE97C10],
        [789AA79B-B1DF-4BA2-860A-7129B39D341F],
        [C90F4EFE-D848-4BAB-96BF-8DC6BF4F6E62],
        [EC6A4ED3-1475-4B0A-8E08-B2F4E095622F],
        [D442B7CA-5825-49D9-9977-D88770304B57],
        [99B70FEE-999B-4D44-83E9-EB8119B15930],
        [3F83ED76-8CC3-4B3D-936A-F528DEB6C045]
        )
    ) AS PivotTable;

(The GUIDS in the 'IN clause are the DetailGUIDs) this almost gets me what I want, except that it is not dynamic and the fact that it is still limited to one data column. (max(sValue)) in this case.

===================

in response to


回答1:


It should be as simple as that:

SELECT *
FROM
(
    SELECT DeviceGUID
          ,DetailGUID 
          ,CONCAT(sValue, iValue, gValue) as [value]
          ,DateStored 
    FROM my_table
) DS
PIVOT
(
    MAX([value]) FOR DetailGUID IN (......)
) PVT


来源:https://stackoverflow.com/questions/63990368/tsql-convert-rows-per-record-to-columns

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!