Oracle: есть ли способ преобразовать данные таким образом? - PullRequest
1 голос
/ 28 апреля 2011

Есть ли способ сопоставить первую таблицу второй таблице с помощью запроса SQL или, если слишком сложно, блока PL / SQL?

Оригинал

--------------------------------------
|  col1   | col2   | col3   | col4   |
--------------------------------------
|  key    | case 1 | case 2 | case 3 |
|  value1 | v1c1   | v1c2   | v1c3   |
|  value2 | v2c1   | v2c2   | v2c3   |
--------------------------------------

Цель

-----------------------------
| key     | case   | result |
-----------------------------
| value1  | case 1 | v1c1   |
| value1  | case 2 | v1c2   |
| value1  | case 3 | v1c3   |
| value2  | case 1 | v2c1   |
| value2  | case 2 | v2c2   |
| value2  | case 3 | v2c3   |
-----------------------------

Исходная таблица может иметь переменное количество столбцов, а ключ - это жестко закодированная строка, которая всегда находится в столбце 1 исходной таблицы.Ни в одной другой строке нет «ключа» в столбце 1, поэтому эта строка является уникальным стержнем.

Спасибо

Ответы [ 4 ]

1 голос
/ 28 апреля 2011

Если разрешен динамический sql, то можно выполнить все ваши требования одним запросом:

SELECT col1 as "key"
       ,extractvalue(dbms_xmlgen.getXMLType('select "' || tc.Column_Name ||
                                           '" as v from Original where col1 = ''key''')
                   ,'/ROWSET/ROW/V') "case"
       ,extractvalue(dbms_xmlgen.getXMLType('select "' || tc.Column_Name ||
                                           '" as v from Original where col1 = ''' ||
                                           replace(col1, '''', '''''') || '''')
                   ,'/ROWSET/ROW/V') "result"
FROM   Original
      ,(SELECT Column_Name
        FROM   All_Tab_Columns tc
        WHERE  tc.Owner = 'YOURSCHEMA'
        and    tc.Table_Name = 'ORIGINAL'
        and    Column_Name != 'COL1'
        ORDER  BY tc.COLUMN_ID) tc
WHERE  col1 != 'key'
ORDER  BY "key"
          ,"case"

Более подробная информация по запросу:

  • dbms_xmlgen.getXMLType возвращает экземпляр XmlType, который в основном является результатом предоставленной строки запроса в виде XML. Формат ROWSET для корневого узла и ROW для каждой строки. Каждый столбец также будет элементом. Создаваемые мной 2 выбора возвращают только одно значение, и для упрощения я дал им псевдоним столбца «V», чтобы я знал, какое значение выбрать из XML.
  • extractValue - это функция, которая возвращает результат выражения XPath из XmlType. '/ ROWSET / ROW / V' возвращает первый V-узел от первого ROW-узла, который находится под корневым узлом ROWSET.
    Abc
1 голос
/ 28 апреля 2011

Я не знаю, какие части могут измениться, но это должно быть началом для вас.Если имена столбцов могут измениться (ключ, случай 1 и т. Д.), Вам потребуется еще один запрос, чтобы получить правильные имена столбцов.Если у вас есть вопросы, не стесняйтесь их задавать:

declare
    v_query VARCHAR2(5000);
    v_case VARCHAR2(255);
    v_colcount PLS_INTEGER;
begin
    -- Get number of columns
    select count(*)
    INTO v_colcount
    from user_tab_columns
    where table_name = 'T1';

    -- Build case statement to get correct value for result column
    v_case := 'case';

    for i in 1 .. v_colcount-1
    loop
        v_case := v_case||' when rn = '||to_char(i)||' then col'||to_char(i+1);
    end loop;

    v_case := v_case||' end result';

    -- Build final query
    v_query := 'select col1 key, ''case ''||rn case, '||v_case||'
        from t1
           cross join (
                select rownum rn
                from dual
                connect by level <= '||to_char(v_colcount-1)||'
            ) cj
        where col1 <> ''key''
        order by key, case';

     -- Display query (would probably be replaced with an insert using execute immediate)
    dbms_output.put_line(v_query);
end;

Это приводит к следующему запросу (при котором ваша исходная таблица называется t1):

select col1 key, 'case '||rn case, case when rn = 1 then col2 when rn = 2 then col3 when rn = 3 then col4 end result
        from t1
           cross join (
                select rownum rn
                from dual
                connect by level <= 3
            ) cj
        where col1 <> 'key'
        order by key, case
1 голос
/ 28 апреля 2011

Попробуйте это:

with data as
(select level l from dual connect by level <= 3)
  select col1,
  'case' || l as "case",
  decode(l,1,col2,2,col3,3,col4) as "values"
  from myTable, data
  order by 1,2;

Приветствия

1 голос
/ 28 апреля 2011

Исходная таблица может иметь переменное количество столбцов

Действительно?

Простой способ - выбрать и объединить нужные детали.

select col1 as key, 'case1' as case, col2 as result
from test
where col1 <> 'key'
union all
select col1 as key, 'case2' as case, col3 as result
from test
where col1 <> 'key'
union all
select col1 as key, 'case3' as case, col4 as result
from test
where col1 <> 'key'

Прямо, но не динамично.

Позже.,.

На основании вашего комментария.,,хотя я не думаю, что это необходимо.

select col1 as key, (select col2 from test where col1='key') as case, col2 as result
from test
where col1 <> 'key'
union all
select col1 as key, (select col3 from test where col1='key') as case, col3 as result
from test
where col1 <> 'key'
union all
select col1 as key, (select col4 from test where col1='key') as case, col4 as result
from test
where col1 <> 'key'

Oracle 11 также поддерживает UNPIVOT, который я не использовал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...