SQL: How to Pivot a Table with Pivot Columns Sharing the Same Name?

时间:2015-10-30 21:24:01

标签: sql sql-server sql-server-2008

I am using SQL Server 2008 R2 version 10.50.1600.1.

I'm trying to pivot a table with strings but the pivot column shares the same name. This is what my data looks like.

+------------+-----------+------------+
| patient_ID | code_type | code_value |
+------------+-----------+------------+
|          1 | ICD9      | V70        |
|          1 | ICD9      | 401.9      |
|          1 | ICD9      | 616        |
|          1 | ICD9      | 338.21     |
|          2 | ICD9      | V10        |
|          2 | ICD9      | 250        |
+------------+-----------+------------+

What I'm trying to get to is this ...

+------------+--------+--------+--------+--------+--------+--------+
| patient_id | ICD9_1 | ICD9_2 | ICD9_3 | ICD9_4 | ICD9_5 | ICD9_x |
+------------+--------+--------+--------+--------+--------+--------+
|          1 | V70    | 401.9  | 616    | 338.21 | null   | null   |
|          2 | V10    | 250    | null   | null   | null   | null   |
+------------+--------+--------+--------+--------+--------+--------+

ICD9_x can stretch to infinity because I don't know how many ICD9 codes there will be for a given patient.

Is there a way to do this in SQL?

Thanks!


Update:

Thanks for all the help! I have received two errors. It looks like pivoting requires the values to be an int because of the sum right? Is there a way to use the pivot table for string values? The ICD9 codes are all strings.

Secondly, I hit an unexpected error. It says that "the number of elements in the select list exceeds the maximum allowed number of 4096 elements." Is there a solution for a large data set?

Thanks again!

2 个答案:

答案 0 :(得分:0)

You can Try something like this. I hope that Works for you.

DECLARE @cols as varchar(max)
DECLARE @query as varchar(max)

select  @cols = (SELECT STUFF((SELECT ',' + QUOTENAME(t.code_type+CAST(row_number() over (partition by patient_id order by patient_id, code_type) as varchar(10)))
    FROM YOURTABLE as t
    FOR XML PATH('')),1,1,''))

select @query = 'select patient_id, ' + @cols + ' from
(select
code_type+CAST(row_number() over (partition by patient_id order by patient_id, code_type) as varchar(10)) as code_type, SUM(code_value) as code_value from YOURTABLE

group by
code_type+CAST(row_number() over (partition by patient_id order by patient_id, code_type) as varchar(10))) d

Pivot (SUM(code_value) for code_type in (' + @cols + ')) p'

EXECUTE(@query)

答案 1 :(得分:0)

您是否有主键或任何列用于订购以确保代码的顺序正确?

如果你有一个,那么你可以将code_type值连接到以下输出:

row_number () OVER (PARTITION BY patient_ID, code_type ORDER BY patient_id, /* codes order column here */)

...然后你就可以将PIVOT(technet info)与连接值一起使用。

以下是一些代码来说明我的意思:


-- Preparing some demo data as per your sample:
DECLARE @YourTable TABLE (
    ID INT IDENTITY (1,1) PRIMARY KEY,
    patient_id INT,
    code_type VARCHAR(20),
    code_value VARCHAR(20)
)

INSERT INTO @YourTable
    (patient_id, code_type, code_value)
VALUES
    (1, 'ICD9', 'V70'),
    (1, 'ICD9', '401.9'),
    (1, 'ICD9', '616'),
    (1, 'ICD9', '338.21'),
    (2, 'ICD9', 'V10'),
    (2, 'ICD9', '250')

-- That should look like your starting point:
SELECT * FROM @YourTable

-- Now we suffix the code_type:
SELECT
    patient_id, 
    code_type + '_' + cast(
            row_number () OVER (PARTITION BY patient_id, code_type ORDER BY patient_id, ID)
            AS VARCHAR(20)
        ) AS code_type, 
    code_value
FROM
    @YourTable

-- ... and finally we pivot:
SELECT
    patient_id,
    ICD9_1, 
    ICD9_2, 
    ICD9_3, 
    ICD9_4
FROM (
    SELECT
        patient_id, 
        code_type + '_' + cast(
                row_number () OVER (PARTITION BY patient_id, code_type ORDER BY patient_id, ID)
                AS VARCHAR(20)
            ) AS code_type, 
        code_value
    FROM
        @YourTable
) data
PIVOT (
    max(code_value)
    -- you need to list all here:
    FOR code_type IN (ICD9_1, ICD9_2, ICD9_3, ICD9_4)
) piv