Oracle SQL-将列转置为行分组

时间:2019-05-06 17:00:34

标签: sql oracle oracle11g grouping transpose

我对一个运行良好的Oracle 11g实例运行以下SQL查询:

SELECT
    TRIM(PART_NM) || TRIM(PART_NO),
    TRIM(MKBY_IND),
    MFG_TYP

FROM
    TblPARTS

WHERE
    ORDER_START_DATE >= (SYSDATE - 365)
    AND
    TO_CHAR(TRIM(PART_NO)) != '99'

产生如下结果:

| Part | Make / Buy |    Area   |
|:----:|:----------:|:---------:|
| AU54 |      M     |    Demo   |
| ZA45 |      M     | Construct |
| AD28 |      B     | Construct |
| SX73 |      B     | Construct |
| MO47 |      M     | Construct |
| IN66 |      B     | Construct |
| RP42 |      M     |    Demo   |
| HF77 |      B     |    Demo   |
| IE43 |      B     |  Personal |
| OX11 |      B     |  Personal |
| ZE45 |      M     |    Demo   |
| JH21 |      M     | Construct |
| AM91 |      M     | Construct |
| DS50 |      M     |    Demo   |
| LE29 |      M     |    Demo   |
| IP91 |      M     |    Demo   |
| ID42 |      M     |    Demo   |
| RI96 |      M     |    Demo   |

我在那里没有问题。但是,已经要求我转置Area列,然后按它对行进行分组。类似于:

|    Part   | Make / Buy |
|:---------:|:----------:|
| CONSTRUCT |  CONSTRUCT |
|    AU54   |      M     |
|    ZA45   |      M     |
|    AD28   |      B     |
|    SX73   |      M     |
|    MO47   |      M     |
|    IN66   |      B     |
|    JH21   |      M     |
|    AM91   |      B     |
|    DEMO   |    DEMO    |
|    RP42   |      M     |
|    HF77   |      M     |
|    ZE45   |      M     |
|    DS50   |      B     |
|    LE29   |      M     |
|    IP91   |      M     |
|    ID42   |      M     |
|    RI96   |      M     |
|  PERSONAL |  PERSONAL  |
|    IE43   |      M     |
|    OX11   |      M     |

简而言之,我希望在“区域”(Area)列(MFG_TYP)字段中找到唯一值,并能够按行将它们分组。应该注意的是,列出的三个条目在我的数据集中是有效的,但是可能会发生变化,因此我不是在寻找静态解决方案,而是在{{1}中的所有唯一值上动态应用转换的方法}列。

我尝试查看这些资源,但是目前不了解如何构建解决方案。任何建议表示赞赏。

2 个答案:

答案 0 :(得分:1)

使用ROLLUP Extension to GROUP BY的快速解决方案:

with
  TblPARTS(Part, Make_Buy, Area) as (
    select 'AU54', 'M', 'Demo' from dual union all
    select 'ZA45', 'M', 'Construct' from dual union all
    select 'AD28', 'B', 'Construct' from dual union all
    select 'SX73', 'B', 'Construct' from dual union all
    select 'MO47', 'M', 'Construct' from dual union all
    select 'IN66', 'B', 'Construct' from dual union all
    select 'RP42', 'M', 'Demo' from dual union all
    select 'HF77', 'B', 'Demo' from dual union all
    select 'IE43', 'B', 'Personal' from dual union all
    select 'OX11', 'B', 'Personal' from dual union all
    select 'ZE45', 'M', 'Demo' from dual union all
    select 'JH21', 'M', 'Construct' from dual union all
    select 'AM91', 'M', 'Construct' from dual union all
    select 'DS50', 'M', 'Demo' from dual union all
    select 'LE29', 'M', 'Demo' from dual union all
    select 'IP91', 'M', 'Demo' from dual union all
    select 'ID42', 'M', 'Demo' from dual union all
    select 'RI96', 'M', 'Demo' from dual union all
    select 'AO42', 'M', 'Public' from dual union all
    select 'OA42', 'B', 'Public' from dual
  ),
  a as (
    select
      Part, Make_Buy, Area,
      GROUPING_ID(Area, Part, Make_Buy) gid
    from TblPARTS
    group by rollup(Area, (Part, Make_Buy))
    having GROUPING_ID(Area, Part, Make_Buy) < 7
  )
select
  coalesce(Part, Area) Part,
  coalesce(Make_Buy, Area) Make_Buy
from a
order by Area, gid desc

输出:

+------------+-----------+
|    PART    |  MAKE_BUY |
+------------+-----------+
| Construct  | Construct |
| AM91       | M         |
| IN66       | B         |
| JH21       | M         |
| SX73       | B         |
| ZA45       | M         |
| AD28       | B         |
| MO47       | M         |
| Demo       | Demo      |
| ZE45       | M         |
| RP42       | M         |
| RI96       | M         |
| LE29       | M         |
| IP91       | M         |
| ID42       | M         |
| HF77       | B         |
| AU54       | M         |
| DS50       | M         |
| Personal   | Personal  |
| OX11       | B         |
| IE43       | B         |
| Public     | Public    |
| OA42       | B         |
| AO42       | M         |
+------------+-----------+

使用Rextester在线进行测试。

答案 1 :(得分:0)

您正在寻找的是这样的

SELECT
    'CONSTRUCT' AS "Part",
    'CONSTRUCT' AS "Make / Buy"
FROM DUAL

UNION

SELECT
    TRIM(PART_NM) || TRIM(PART_NO) AS "Part",
    TRIM(MKBY_IND) AS "Make / Buy"
FROM
    TblPARTS
WHERE
    ORDER_START_DATE >= (SYSDATE - 365)
    AND    TO_CHAR(TRIM(PART_NO)) != '99'
    AND    MFG_TYP = 'Construct'

UNION

SELECT
    'DEMO' AS "Part",
    'DEMO' AS "Make / Buy"
FROM DUAL

UNION

SELECT
    TRIM(PART_NM) || TRIM(PART_NO) AS "Part",
    TRIM(MKBY_IND) AS "Make / Buy"
FROM
    TblPARTS
WHERE
    ORDER_START_DATE >= (SYSDATE - 365)
    AND    TO_CHAR(TRIM(PART_NO)) != '99'
    AND    MFG_TYP = 'Demo'

UNION

SELECT
    'PERSONAL ' AS "Part",
    'PERSONAL ' AS "Make / Buy"
FROM DUAL

UNION

SELECT
    TRIM(PART_NM) || TRIM(PART_NO)) AS "Part",
    TRIM(MKBY_IND) AS "Make / Buy"
FROM
    TblPARTS
WHERE
    ORDER_START_DATE >= (SYSDATE - 365)
    AND    TO_CHAR(TRIM(PART_NO)) != '99'
    AND    MFG_TYP = 'Personal'