2016-12-21 3 views
1

Как мы можем написать код, который PLSQL переставляет значения таблицы А в таблице В.Транспонирование таблицы в Oracle

Таблица 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 не является нулевым. если какой-либо из величины равна нулю, то не должно не ЗАП в таблице B. Например, если val2 равно нулю, то

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

. , Я не уверен на 100%, я понимаю состояние «NULL». Является ли намерение просто отфильтровывать значения «NULL»? –

+0

Да, если есть какое-либо значение NULL для любого столбца таблицы A, то оно не должно отображаться в таблице B в столбцах типа и значения – CodingFreak

+0

Что такое «это»? Ряд? Колонка? –

ответ

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.

+0

Этот запрос охватывает нулевое условие? – CodingFreak

+0

@mathguy. , , Кажется, что OP хочет, чтобы обе строки и столбцы были удалены, поэтому он использует тот же метод для обоих. –

1

В Oracle 11.1 и выше вы можете использовать UNPIVOT. Я добавил некоторые тестовые данные, чтобы показать лечение NULL. (Помните, что в Oracle, пустая строка, '', такая же, как NULL.)

with 
    table_a (rec_id, col1, col2, col3) as (
     select 2, 'val1', 'val2', 'val3' from dual union all 
     select 3, 'val4', '' , 'val6' from dual union all 
     select 8, '' , '' , ''  from dual 
    ) 
-- end of test data; query begins below this line 
select * 
from table_a 
unpivot (value for type in (col1 as 'col1', col2 as 'col2', col3 as 'col3')) 
; 


REC_ID TYPE VALUE 
------ ---- ----- 
    2 col1 val1 
    2 col2 val2 
    2 col3 val3 
    3 col1 val4 
    3 col3 val6 
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; 

Здесь вы должны изменить TABLEA с вашим именем таблицы и REC_ID в соответствии с вашим ID таблицы , вы должны создать таблицу назначения перед запуском кода и заменить TABLEB на имя своей целевой таблицы. Он также будет покрывать нулевое состояние. Комментируемая заявка полезна при отладке кода

Смежные вопросы