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
Dane testowe i dane wyjściowe:
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
Edytuj :Wyjaśnienie
W odpowiedzi użyłem with
klauzula tylko po to, aby podzielić rozwiązanie na czytelne kroki. Możesz je przenieść do with
klauzula głównego zapytania, jeśli jest to dla Ciebie wygodniejsze. W każdym razie:podzapytanie a
odczytuje dane z tabeli attributes
i dodaje numer dla wierszy, więc dla każdego działu są one zawsze numerowane od 1. Użyłem numer_wiersza()
za to. Podzapytanie e
związki (wszystkie) wymagają atrybutów i odpowiednio je numerują. Liczby wygenerowane w obu podzapytaniach są następnie używane w łączeniu głównym:a.department=e.department and a.rn=e.rn
.
Alternatywna 1 - jeśli używasz Oracle 11g, możesz użyć unpivot
. Zobacz, co jest generowane przez podzapytanie i jak jest połączone z attributes
tabela:
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;
Alternatywna 2 - z hierarchicznym generatorem podzapytań (podzapytanie r
), zrealizowany przez connect by
które proste tworzy liczby od 1, 2, 3, które następnie są łączone z employees
a odpowiedni atrybut jest dołączony jako wartość w case
klauzula. Reszta jest wykonana w podobny sposób jak w oryginalnej odpowiedzi.
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
Wszystkie trzy wersje dawały mi ten sam efekt. Testowałem również pierwszą opcję na podobnej tabeli z 100k wierszy i uzyskałem wynik w kilka sekund (dla 5 atrybutów). Przetestuj wszystkie rozwiązania i spróbuj je zrozumieć. Jeśli możesz użyć wersji unpivot, wolałbym to.Przepraszam za opóźnione wyjaśnienie i wszelkie błędy językowe.