【问题标题】:Conditional transpose columns into rows in oracle sql在oracle sql中条件性将列转置为行
【发布时间】:2015-09-15 21:05:39
【问题描述】:

我的表 mtinre 中有这一行:

  INREPRCO   INRESELO   INRECAPI   INRECFRA   INRECAPO
---------- ---------- ---------- ---------- ----------
     32.42       1.87          1                     5

我构建了一个查询来将此行转置为每列 5 个不同的行。

SELECT CASE pivot
          WHEN 1 THEN 'VAPRS'
          WHEN 2 THEN 'VAFRC'
          WHEN 3 THEN 'VACTA'
          WHEN 4 THEN 'VIMSL'
          WHEN 5 THEN 'VINEM'
       END
          component,
       CASE pivot
          WHEN 1 THEN inreprco
          WHEN 2 THEN inrecfra
          WHEN 3 THEN inrecapo
          WHEN 4 THEN inreselo
          WHEN 5 THEN inreinem
          ELSE NULL
       END
          VALUE,
       CASE pivot
          WHEN 4
          THEN
             (NVL (inreprco, 0) + NVL (inrecfra, 0) + NVL (inrecapo, 0))
          WHEN 5
          THEN
             (NVL (inreprco, 0) + NVL (inrecfra, 0) + NVL (inrecapo, 0))
          ELSE
             NULL
       END
          AS base
  FROM mtinre,
       (    SELECT ROWNUM pivot
              FROM DUAL
        CONNECT BY LEVEL <= 5)

输出是:

COMPONENT      VALUE       BASE
--------- ---------- ----------
VAPRS          32.42           
VAFRC                          
VACTA              5           
VIMSL           1.87      37.42
VINEM            .94      37.42

但是这 5 个字段(INREPRCO、INRESELO、INRECAPI、INRECFRA、INRECAPO)可以有 null 或零 (0) 值。所以我只需要选择那些有价值的人。 在最后一个例子中,只给我看:

COMPONENT      VALUE       BASE
--------- ---------- ----------
VAPRS          32.42           
VACTA              5           
VIMSL           1.87      37.42
VINEM            .94      37.42

我尝试设置一些 where 条件,但 connect by level 语句总是为我创建 5 行。

所以,我改变了我的查询并做了这个:

SELECT *
  FROM (SELECT CASE pivot
                  WHEN 1 THEN 'VAPRS'
                  WHEN 2 THEN 'VAFRC'
                  WHEN 3 THEN 'VACTA'
                  WHEN 4 THEN 'VIMSL'
                  WHEN 5 THEN 'VINEM'
               END
                  component,
               CASE pivot
                  WHEN 1 THEN inreprco
                  WHEN 2 THEN inrecfra
                  WHEN 3 THEN inrecapo
                  WHEN 4 THEN inreselo
                  WHEN 5 THEN inreinem
                  ELSE NULL
               END
                  VALUE,
               CASE pivot
                  WHEN 4
                  THEN
                     (  NVL (inreprco, 0)
                      + NVL (inrecfra, 0)
                      + NVL (inrecapo, 0))
                  WHEN 5
                  THEN
                     (  NVL (inreprco, 0)
                      + NVL (inrecfra, 0)
                      + NVL (inrecapo, 0))
                  ELSE
                     NULL
               END
                  AS base
          FROM mtinre,
               (    SELECT ROWNUM pivot
                      FROM DUAL
                CONNECT BY LEVEL <= 5))
 WHERE VALUE IS NOT NULL

它可以工作,但是有没有其他方法可以在不使用 sub select 语句的情况下做到这一点? 有什么建议吗?

谢谢 菲利普

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    使用 UNPIVOT 和一个小技巧就可以完成这项工作。几乎所有表都有一个 id 列(主键或唯一键)。假设表有 id_col 作为 id 列,这个查询将完成这项工作

    SQL> WITH table_(id_col, inreprco,inreselo,inrecapi,inrecfra,inrecapo) AS
      2   (SELECT 1, 32.42,1.87,0.94,NULL,5 FROM dual UNION ALL
      3    SELECT 2, 33.43,2.87,0.87,12,9 FROM dual ),
      4  ---------
      5  -- End of data preparation
      6  ---------
      7  table2_ AS (SELECT id_col, component, VALUE
      8               FROM table_
      9            UNPIVOT (VALUE FOR component IN (inreprco AS 'VAPRS', inrecfra AS 'VAFRC', inrecapo AS 'VACTA', inreselo AS 'VIMSL', inrecapi AS 'VINEM')))
     10  select a.id_col,
     11         a.COMPONENT,
     12         a.VALUE,
     13         CASE WHEN a.component IN ('VIMSL', 'VINEM') THEN nvl(b.inreprco, 0) + nvl(b.inrecfra, 0) + NVL(b.inrecapo, 0) ELSE NULL END AS base
     14    FROM table2_ a
     15    INNER JOIN table_ b
     16       ON b.id_col = a.id_col;
    
        ID_COL COMPONENT      VALUE       BASE
    ---------- --------- ---------- ----------
             1 VAPRS          32.42 
             1 VACTA              5 
             1 VIMSL           1.87      37.42
             1 VINEM           0.94      37.42
             2 VAPRS          33.43 
             2 VAFRC             12 
             2 VACTA              9 
             2 VIMSL           2.87      54.43
             2 VINEM           0.87      54.43
    
    9 rows selected 
    

    但是如果没有 Id 列,则将连接修改为交叉连接即可,但如果表中只有一行,则会返回正确的结果。

       SQL> WITH table_(inreprco,inreselo,inrecapi,inrecfra,inrecapo) AS
          2   (SELECT 32.42,1.87,0.94,NULL,5 FROM dual),
          3  ---------
          4  -- End of data preparation
          5  ---------
          6  table2_ AS (SELECT component, VALUE
          7               FROM table_
          8            UNPIVOT (VALUE FOR component IN (inreprco AS 'VAPRS', inrecfra AS 'VAFRC', inrecapo AS 'VACTA', inreselo AS 'VIMSL', inrecapi AS 'VINEM')))
          9  select a.COMPONENT,
         10         a.VALUE,
         11         CASE WHEN a.component IN ('VIMSL', 'VINEM') THEN nvl(b.inreprco, 0) + nvl(b.inrecfra, 0) + NVL(b.inrecapo, 0) ELSE NULL END AS base
         12    FROM table2_ a
         13    CROSS JOIN table_ b
         14  /
    
        COMPONENT      VALUE       BASE
        --------- ---------- ----------
        VAPRS          32.42 
        VACTA              5 
        VIMSL           1.87      37.42
        VINEM           0.94      37.42
    

    或者等待有其他方法的人;)

    【讨论】:

    • 极好的解决方案。但是有一个问题。我需要从输出中删除值为零 (0) 的字段。
    • 使用合适的WHERE 条件可以删除不需要的记录。请让我们知道您在谈论哪个领域。
    猜你喜欢
    • 1970-01-01
    • 2021-06-13
    • 2015-04-26
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    • 2021-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多