在oracle中转置表

时间:2016-12-21 02:39:20

标签: sql oracle oracle12c

我们如何编写一个plsql代码,将表A的值转换为表B.

表A

rec_id ||  col1  || col2  ||  col3
   2        val1     val2       val3
   3        val4     val5       val6

表B中所需的输出

表B

 rec_id   ||   type  ||   value
 2                  col1         val1
 2                  col2         val2
 2                   col3         val3
 3                  col4         val5
 3                  col5         val5
 3                   col6         val6

仅当val1或val2或val3不为空时。如果任何值为null,那么表B中不应该有rec。例如,如果val2为null,则

    rec_id   ||   type  ||   value
       2         col1         val1
       2         col3         val3

3 个答案:

答案 0 :(得分:1)

在Oracle 11.1及更高版本中,您可以使用AdditionalDataId。我添加了一些测试数据来显示UNPIVOT的处理方法。 (请记住,在Oracle中,空字符串NULL''相同。)

NULL

答案 1 :(得分:0)

您可以使用union all(以及其他方法)执行此操作:

select rec_id, 'col1' as type, col1 as value from t where col1 is not null union all
select rec_id, 'col2' as type, col2 as value from t where col2 is not null union all
select rec_id, 'col3' as type, col3 as value from t where col3 is not null;

您似乎想要消除任何出现NULL的行和列:

select rec_id, type, value
from (select t.*,
             (case when count(*) over (partition by type) = count(value) over (partition by type)
                   then 1 else 0
              end) as no_null_type,
             (case when count(*) over (partition by recid) = count(value) over (partition by recid)
                   then 1 else 0
              end) as no_null_recid
      from (select rec_id, 'col1' as type, col1 as value from t union all
            select rec_id, 'col2' as type, col2 as value from t union all
            select rec_id, 'col3' as type, col3 as value from t
           ) t
     ) t
where no_null_type = 1 and no_null_recid = 1;

在Oracle 12c中,您可以使用横向连接:

select t.rec_id, x.type, x.value
from t cross apply
     (select 'col1' as type, col1 as value from dual union all
      select 'col2' as type, col2 as value from dual union all
      select 'col3' as type, col3 as value from dual
     ) x
where value is not null;

这样做的好处是只扫描一次表。您可以应用类似的逻辑来删除NULL

答案 2 :(得分:0)

我知道您显示的表名不是您想要运行查询的实际表,它可能有超过3列。

所以我想出了一个PLSQL程序(如果你想在sql中,那么其他答案会帮助你)

    DECLARE
      SQLSELECT VARCHAR2(1000);
      SQLINSERT VARCHAR2(1000);
      TYPE TCur IS REF CURSOR;
        cur TCur;
      TYPE TRec IS RECORD (ID INT,
                           COL_VAL VARCHAR2(20));
      v_rec TRec;
    BEGIN
      FOR rec IN
      (SELECT column_name
        FROM all_tab_columns
        WHERE table_name = 'TABLEA')
      LOOP
      IF (rec.column_name <> 'REC_ID') THEN
        SQLSELECT:= 'SELECT ID,'||rec.column_name||' column_name FROM TABLEA 
                     where '||rec.column_name||' is not null';
        OPEN cur FOR SQLSELECT;
        LOOP
          FETCH cur INTO v_rec;
          EXIT WHEN cur%notfound;
         -- DBMS_OUTPUT.PUT_LINE(v_rec.ID||' '||v_rec.COL_VAL||' '||rec.column_name);
          SQLINSERT:= 'INSERT INTO TABLEB VALUES(:1, :2, :3)';
          --DBMS_OUTPUT.PUT_LINE(SQLINSERT);
          EXECUTE IMMEDIATE SQLINSERT USING v_rec.ID,v_rec.COL_VAL,rec.column_name;
        END LOOP;
      END IF;
    END LOOP;
    END;

在这里,您必须根据您的表格ID更改TABLEAREC_ID,您必须在运行代码之前创建目标表,并将TABLEB替换为您的目的地表名称。它还将涵盖无效条件。在调试代码时,注释语句很有用