SQL查询 - 将单元格转换为列

时间:2012-09-03 16:15:45

标签: sql sql-server pivot

我有一个返回类似

的项目的查询
Item    --  Code   --  Thing
------------------------------
Item A  --  Code A --  Thing 1
Item A  --  Code A --  Thing 2
Item A  --  Code A --  Thing 3
Item A  --  Code A --  Thing 4
Item B  --  Code B --  Thing x
Item B  --  Code B --  Thing y
Item C  --  Code C --  Thing z
Item C  --  Code C --  Thing a
Item C  --  Code C --  Thing b
Item C  --  Code C --  Thing c

我想把它变成这样的东西

Item    --  Code   --  Thing 1 -- Thing 2 -- Thing 3 -- Thing 4 -- Thing 5
---------------------------------------------------------------------------
Item A  --  Code A --  Thing 1 -- Thing 2 -- Thing 3 -- Thing 4 -- NULL
Item B  --  Code B --  Thing x -- Thing y -- NULL    -- NULL    -- NULL
Item C  --  Code C --  Thing a -- Thing b -- Thing c -- Thing d -- NULL

任何超过5的项目都可以忽略。


更新

添加 “ROW_NUMBER()结束(Table.Id按Table2.Id排序)”在我的查询中我现在得到:

Item    --  Code   --  Thing  -- Index
---------------------------------------
Item A  --  Code A --  Thing 1 -- 1
Item A  --  Code A --  Thing 2 -- 2
Item A  --  Code A --  Thing 3 -- 3
Item A  --  Code A --  Thing 4 -- 4
Item B  --  Code B --  Thing x -- 1
Item B  --  Code B --  Thing y -- 2
Item C  --  Code C --  Thing z -- 1
Item C  --  Code C --  Thing a -- 2
Item C  --  Code C --  Thing b -- 3
Item C  --  Code C --  Thing c -- 4

这允许我使用Pivot功能并相应地更改数据。 仍在努力,所以任何帮助都非常感激。

2 个答案:

答案 0 :(得分:1)

您可以使用PIVOT Operator

以下是针对类似问题的示例查询

SELECT *
FROM
    (
    SELECT Contact_Id AS CT
          , [Age]
          , [Sex]
          , [State]
          , [Country]
          , [Keyword]
          , [Married]
          , [Kids]
          , [Car]
     FROM
         (SELECT c.PropertyName
               , c.ValueString
               , c.Contact_Id
          FROM
              ContactProfiles c) AS ctp
         PIVOT (max(ctp.ValueString) FOR PropertyName IN ([Age], [Sex], [State], [Country], [Keyword], [Married], [Kids], [Car])) AS PivotTable
         ) AS pvt

WHERE
    pvt.[Age] > 18

答案 1 :(得分:0)

(首先尝试不起作用) 一种干净的编码方式是:

    SELECT
        Item,
        Code,
        Thing1 = Case When Thing = 'Thing 1' Then 'Thing 1' Else Null End,
        Thing2 = Case When Thing = 'Thing 2' Then 'Thing 2' Else Null End,
        Thing3 = Case When Thing = 'Thing 3' Then 'Thing 3' Else Null End,
        Thing4 = Case When Thing = 'Thing 4' Then 'Thing 4' Else Null End,
        Thing5 = Case When Thing = 'Thing 5' Then 'Thing 5' Else Null End
   FROM [Items]
   WHERE Thing BETWEEN 'Thing 1' AND 'Thing 5' -- preselection should improve performance
   GROUP BY 
        Item,
        Code,
        Thing1 = Case When Thing = 'Thing 1' Then 'Thing 1' Else Null End,
        Thing2 = Case When Thing = 'Thing 2' Then 'Thing 2' Else Null End,
        Thing3 = Case When Thing = 'Thing 3' Then 'Thing 3' Else Null End,
        Thing4 = Case When Thing = 'Thing 4' Then 'Thing 4' Else Null End,
        Thing5 = Case When Thing = 'Thing 5' Then 'Thing 5' Else Null End

可以使用,因为您有一个已知的,有限数量的列可以进行透视。 PIVOT功能是另一种方式,但我不熟悉这个。

(第二次尝试)这有效!

    DECLARE @Items TABLE
    (
        Item    char(1),
        Code    char(1),
        Thing   char(1)
    )
    INSERT INTO @Items
    SELECT 'A', 'A', '1'
    UNION
    SELECT 'A', 'A', '2'
    UNION
    SELECT 'A', 'A', '3'
    UNION
    SELECT 'A', 'A', '4'
    UNION
    SELECT 'B', 'B', 'x'
    UNION
    SELECT 'B', 'B', 'y'
    UNION
    SELECT 'C', 'C', 'f'
    UNION
    SELECT 'C', 'C', 'g'
    UNION
    SELECT 'C', 'C', 'h'
    UNION 
    SELECT 'C', 'C', 'j'

    SELECT
        Items.Item,
        Items.Code,
        Thing1 = Max(Case When OrderedItems.ThingPlace = 1 Then OrderedItems.Thing Else Null End),
        Thing2 = Max(Case When OrderedItems.ThingPlace = 2 Then OrderedItems.Thing Else Null End),
        Thing3 = Max(Case When OrderedItems.ThingPlace = 3 Then OrderedItems.Thing Else Null End),
        Thing4 = Max(Case When OrderedItems.ThingPlace = 4 Then OrderedItems.Thing Else Null End),
        Thing5 = Max(Case When OrderedItems.ThingPlace = 5 Then OrderedItems.Thing Else Null End)
    FROM @Items Items
        LEFT OUTER JOIN 
        (
            SELECT
                Code, Thing, 
                ThingPlace = Row_Number() OVER (PARTITION BY Code ORDER BY Thing)
            FROM @Items
            GROUP BY Code, Thing
        ) OrderedItems
            ON OrderedItems.Code = Items.Code
    WHERE OrderedItems.ThingPlace Is Null OR OrderedItems.ThingPlace <= 5
    GROUP BY
        Items.Item,
        Items.Code

结果:

A A 1 2 3 4 NULL

B B x y NULL NULL NULL

C C f g h j NULL

诀窍是先建立一个有序的事物清单。我只使用代码进行查找,因为在这种情况下,这似乎是给出的数据是关键(项目并不重要)。您可能必须扩展连接连接。 使用有序列表,然后按顺序排除第六位以上的所有事物。这只有在Thing(s)实际上是一个自然顺序时才有效 - 否则它会回到原点,以便首先找出Thing(s)是什么。