有条件地将列转换为oracle sql中的行

时间:2015-09-15 11:00:10

标签: sql oracle

我的表格中有这一行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)可以具有零或零(0)值。所以我只需要选择那些有价值的东西。 在最后一个例子中,只显示我:

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

我试图把一些条件放在哪里,但是按层次连接语句总是让我产生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

它有效,但有没有其他方法可以不使用子选择语句? 有什么建议吗?

由于 菲利普

1 个答案:

答案 0 :(得分:3)

使用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

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