Oracle
 sql >> база данни >  >> RDS >> Oracle

Как да свържете хоризонтални стойности на таблица с вертикални стойности на друга таблица в базата данни на Oracle

with a as (
    select a.*, row_number() over (partition by department order by attributeID) rn
      from attributes a),
  e as (
    select employeeId, department, attribute1, 1 rn from employees union all
    select employeeId, department, attribute2, 2 rn from employees union all
    select employeeId, department, attribute3, 3 rn from employees
  )
select e.employeeId, a.attributeid, e.department, a.attribute, a.meaning, 
       e.attribute1 as value 
  from e join a on a.department=e.department and a.rn=e.rn 
  order by e.employeeId, a.attributeid

Тестови данни и изход:

create table employees (employeeID number(3), name varchar2(10), department varchar2(5), age number(3), attribute1 varchar2(10), attribute2 varchar2(10), attribute3 varchar2(10));
insert into employees values (1, 'john', 'IT', 22, 'attr1val1', 'attr2val2',  null);
insert into employees values (2, 'jane', 'HR', 32, 'attr1val3', 'attr2val4',  'attr3val5');
insert into employees values (3, 'joe',  'HR', 23, 'attr1val6', 'attr2val7',  'attr3val8');
insert into employees values (4, 'jack', 'IT', 45, 'attr1val9', 'attr2val10', null);

create table attributes (attributeID number(3), department varchar2(10), attribute varchar2(10), meaning varchar2(10));
insert into attributes values (1, 'IT', 'attribute1', 'laptoptype');
insert into attributes values (2, 'IT', 'attribute2', 'networkloc');
insert into attributes values (3, 'HR', 'attribute1', 'location');
insert into attributes values (4, 'HR', 'attribute2', 'position');
insert into attributes values (5, 'HR', 'attribute3', 'allocation');

EMPLOYEEID ATTRIBUTEID DEPARTMENT ATTRIBUTE  MEANING    VALUE
---------- ----------- ---------- ---------- ---------- ----------
         1           1 IT         attribute1 laptoptype attr1val1
         1           2 IT         attribute2 networkloc attr2val2
         2           3 HR         attribute1 location   attr1val3
         2           4 HR         attribute2 position   attr2val4
         2           5 HR         attribute3 allocation attr3val5
         3           3 HR         attribute1 location   attr1val6
         3           4 HR         attribute2 position   attr2val7
         3           5 HR         attribute3 allocation attr3val8
         4           1 IT         attribute1 laptoptype attr1val9
         4           2 IT         attribute2 networkloc attr2val10

Редактиране :Обяснение

В отговор използвах with клауза само за разделяне на решението на четливи стъпки. Можете да ги преместите в from клауза на основната заявка, ако е по-удобно за вас. Както и да е:подзаявка a чете данни от attributes на таблицата и добавя номер за редовете, така че за всеки отдел те винаги са номерирани от 1. Използвах row_number() за това. Подзаявка e обединенията (всички) изискват атрибути и ги номерират съответно. Числата, генерирани в двете подзаявки, след това се използват в основното съединение:a.department=e.department and a.rn=e.rn .

Алтернатива 1 - ако използвате Oracle 11g, можете да използвате unpivot . Вижте какво се генерира от подзаявка и как се обединява с attributes таблица:

with e as (
    select employeeId, name, department, attribute, value from employees
      unpivot (value for attribute in ("ATTRIBUTE1", "ATTRIBUTE2", "ATTRIBUTE3"))  
  )
select e.employeeId, a.attributeid, e.department, a.attribute, 
       a.meaning, e.value 
  from e join attributes a on a.department=e.department 
                          and lower(a.attribute)=lower(e.attribute)
  order by e.employeeId, a.attributeid;

Алтернатива 2 - с генератор на йерархична подзаявка (подзаявка r ), реализиран от connect by което просто създава числа от 1, 2, 3, които след това се свързват с employees и правилният атрибут е прикрепен като стойност в case клауза. Останалото се прави по подобен начин като в оригиналния отговор.

with a as (
    select a.*, row_number() over (partition by department order by attributeID) rn
      from attributes a),
  r as (select level rn from dual connect by level<=3),
  e as (
    select employeeId, department, rn,
           case when r.rn = 1 then attribute1
                when r.rn = 2 then attribute2
                when r.rn = 3 then attribute3
           end value
      from employees cross join r
  )
select e.employeeId, a.attributeid, e.department, a.attribute,
       a.meaning, e.value
  from e join a on a.department=e.department and a.rn=e.rn
  order by e.employeeId, a.attributeid

И трите версии ми дадоха еднакъв резултат. Също така тествах първата опция на подобна таблица със 100 000 реда и получих изход за няколко секунди (за 5 атрибута). Моля, тествайте всички решения и се опитайте да ги разберете. Ако можете да използвате unpivot версия, бих предпочел това. Извинете за забавеното обяснение и всички езикови грешки.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. низовият литерал е твърде дълъг - как да присвоите дълги xml данни към типа данни clob в oracle 11g r2

  2. Създаване на таблица с база данни в PL/SQL процедура

  3. Резултат от формата за изваждане на времето

  4. Вложените скоби в клаузата FROM валиден ли е синтаксисът на Oracle SQL?

  5. Има ли Oracle, еквивалентен на ИЗХОДНИЯТ ИЗХОД на SQL Server INSERTED.*?