Kettch19
Kettch19

Reputation: 404

SQL Query - Almost pivot table-like?

Another stupid question here regarding a SQL scenario.

Given data such as:

FieldKey    DocumentKey FieldId FieldValue
1   00001c55-aab3-4df8-a07e-8eac162fa075    TITLE   Mass Import 18355
2   00001c55-aab3-4df8-a07e-8eac162fa075    1   00001c55-aab3-4df8-a07e-8eac162fa075
3   00001c55-aab3-4df8-a07e-8eac162fa075    2   9F-2F-CF-76-27-E7-5B-C9-27-CE-23-45-68-3F-E2-89
4   00001c55-aab3-4df8-a07e-8eac162fa075    3   18355
5   00001c55-aab3-4df8-a07e-8eac162fa075    4   94-3C-84-B1-6A-AA-FD-25-F1-C0-D2-43-CD-D3-57-D6
6   00001c55-aab3-4df8-a07e-8eac162fa075    5   Created by C# mass import
7   00002205-00D3-4495-B65A-A7B1FD2AE7F2    TITLE   Mass Import 1494780
8   00002205-00D3-4495-B65A-A7B1FD2AE7F2    1   00002205-00D3-4495-B65A-A7B1FD2AE7F2
9   00002205-00D3-4495-B65A-A7B1FD2AE7F2    2   870386312
10  00002205-00D3-4495-B65A-A7B1FD2AE7F2    3   1494780
11  00002205-00D3-4495-B65A-A7B1FD2AE7F2    4   -1929051324
13  00002342-6de0-4110-b576-fd32f96b2858    TITLE   Mass Import 387008
14  00002342-6de0-4110-b576-fd32f96b2858    1   00002342-6de0-4110-b576-fd32f96b2858
15  00002342-6de0-4110-b576-fd32f96b2858    2   B0-CB-DF-ED-48-DC-C4-E8-B0-6F-1B-1D-81-2D-6D-51
16  00002342-6de0-4110-b576-fd32f96b2858    3   387008

With table structure:

[FieldKey] [bigint] IDENTITY(1,1) NOT NULL,
[DocumentKey] [char](36) NOT NULL,
[FieldId] [varchar](10) NOT NULL,
[FieldValue] [varchar](255) NOT NULL

What is the best way to flip this data horizontally? Ideally:

DocumentKey                             TITLE    1    2    3    4    5
00001c55-aab3-4df8-a07e-8eac162fa075    mytitle  val1 val2 val3 val4 val5
00002205-00D3-4495-B65A-A7B1FD2AE7F2    mytitle2 val6 val7 val8 val9
00002342-6de0-4110-b576-fd32f96b2858    mytitle3 vl10 vl11 vl12

I thought a pivot table might work and it is close, but the problem is I don't need an aggregation which is required for a SQL pivot. I just want to flip the data. The number of columns (1-5 plus TITLE in my example) could be anywhere between TITLE plus 1-30.

Maybe I'm just being dense, but any ideas would be appreciated.

Upvotes: 0

Views: 838

Answers (2)

Arion
Arion

Reputation: 31249

I think that you are on the right track with a PIVOT. You are going to have a aggregate on the value column. But as you say you will have 1-30 column plus the title column. That requires a dynamic pivot

Here is a suggestion (that is only for SQL Server 2005+):

Test data

CREATE TABLE Table1
(
    [FieldKey] [bigint] NOT NULL,
    [DocumentKey] [char](36) NOT NULL,
    [FieldId] [varchar](10) NOT NULL,
    [FieldValue] [varchar](255) NOT NULL
)
INSERT INTO Table1
VALUES
    (1,'00001c55-aab3-4df8-a07e-8eac162fa075','TITLE','Mass Import 18355'),
    (2,'00001c55-aab3-4df8-a07e-8eac162fa075','1','00001c55-aab3-4df8-a07e-8eac162fa075'),
    (3,'00001c55-aab3-4df8-a07e-8eac162fa075','2','9F-2F-CF-76-27-E7-5B-C9-27-CE-23-45-68-3F-E2-89'),
    (4,'00001c55-aab3-4df8-a07e-8eac162fa075','3','18355'),
    (5,'00001c55-aab3-4df8-a07e-8eac162fa075','4','94-3C-84-B1-6A-AA-FD-25-F1-C0-D2-43-CD-D3-57-D6'),
    (6,'00001c55-aab3-4df8-a07e-8eac162fa075','5','Created by C# mass import'),
    (7,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','TITLE','Mass Import 1494780'),
    (8,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','1','00002205-00D3-4495-B65A-A7B1FD2AE7F2'),
    (9,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','2','870386312'),
    (10,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','3','1494780'),
    (11,'00002205-00D3-4495-B65A-A7B1FD2AE7F2','4','-1929051324'),
    (13,'00002342-6de0-4110-b576-fd32f96b2858','TITLE','Mass Import 387008'),
    (14,'00002342-6de0-4110-b576-fd32f96b2858','1','00002342-6de0-4110-b576-fd32f96b2858'),
    (15,'00002342-6de0-4110-b576-fd32f96b2858','2','B0-CB-DF-ED-48-DC-C4-E8-B0-6F-1B-1D-81-2D-6D-51'),
    (16,'00002342-6de0-4110-b576-fd32f96b2858','3','387008')

Find the unique columns

DECLARE @cols VARCHAR(MAX)
;WITH CTE
AS
(
    SELECT
        ROW_NUMBER() OVER(PARTITION BY Table1.FieldId 
                              ORDER BY Table1.FieldId) AS RowNbr,
        Table1.*
    FROM
        Table1
)
SELECT @cols=STUFF
(
    (
        SELECT 
            ',' +QUOTENAME(CTE.FieldId)
        FROM
            CTE
        WHERE
            CTE.RowNbr=1
        ORDER BY 
            LEN(CTE.FieldId) DESC,
            CTE.FieldId
        FOR XML PATH('')
    )
,1,1,'')

We need to order so that TITLE comes first. The FOR XML PATH is to concat the columns.

Dynamic pivot

DECLARE @query NVARCHAR(4000)=
N'SELECT
    *
FROM
(
    SELECT
        Table1.DocumentKey,
        Table1.FieldId,
        Table1.FieldValue
    FROM
        Table1
) AS p
PIVOT
(
    MAX(FieldValue)
    FOR FieldId IN('+@cols+')
) AS p'
EXECUTE(@query)

Clean up after myself (not required)

DROP TABLE Table1

Upvotes: 2

jim31415
jim31415

Reputation: 8818

If you're using SQL Server 2005+, you can use PIVOT operator.

select [DocumentKey], [TITLE], [1], [2], [3], [4], [5] 
from (select [DocumentKey], FieldId, FieldValue from TableName) t
    pivot (max(FieldValue) for FieldID in ([TITLE], [1], [2], [3], [4], [5])) as pvt
order by [DocumentKey]

You would have to add the additional columns, 6 - 30.

Upvotes: 2

Related Questions