Oracle 动态连接(或移动行)
Oracle dynamic join (or move row)
我是运行 Oracle 11g,需要将某些行分成列,但列数未确定,所以我需要动态地进行。
最初我想分成多个查询,然后再加入它们,但它似乎不是最合适的,而且我无法使其动态化。
这是我的 table:
的简化示例
CREATE TABLE foo (
id NUMBER,
cod NUMBER,
val NUMBER,
dat DATE
);
INSERT INTO foo VALUES(1, 35, 58.10, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(2, 45, 38.50, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(3, 45, 3.89, TO_DATE('20-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(4, 35, 102.0, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(5, 75, 69.32, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(6, 75, 74.65, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(7, 45, 32.8, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(8, 75, 12.76, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(1, 35, 38.50, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(2, 45, 3.89, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(3, 45, 102.0, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(4, 35, 69.32, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(5, 75, 74.65, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(6, 75, 32.8, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(7, 45, 38.50, TO_DATE('30-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(8, 75, 3.89, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
SELECT a.cod, a.val, b.cod, b.val
FROM foo a, (
SELECT id, cod, val
FROM foo
WHERE dat = TO_DATE('01-07-2019', 'DD-MM-YYYY')
) b
WHERE a.id = b.id AND
a.dat = TO_DATE('01-08-2019', 'DD-MM-YYYY');
产量(按 COD 排序):
COD|VAL |COD|VAL |
---|-----|---|-----|
35| 38.5| 35| 58.1|
35|69.32| 35| 102|
45| 3.89| 45| 38.5|
75|74.65| 75|69.32|
75| 32.8| 75|74.65|
75| 3.89| 75|12.76|
我需要这些行只有一个不同的 COD,其他的将排列在新的列中。
预计:
COD 35 | COD 45 | COD 75 | <- illustrative
-------------------|-------------------|-------------------|
COD|VAL |COD|VAL |COD|VAL |COD|VAL |COD|VAL |COD|VAL |
---|-----|---|-----|---|-----|---|-----|---|-----|---|-----|
35| 38.5| 35| 58.1| 45| 3.89| 45| 38.5| 75|74.65| 75|69.32|
35|69.32| 35| 102| | | | | 75| 32.8| 75|74.65|
| | | | | | | | 75| 3.89| 75|12.76|
谢谢
我解决了以下问题:
DECLARE
p_cod_str VARCHAR2(100) := '35, 75, 45';
i_prv VARCHAR2(10);
q_loop VARCHAR2(1000);
q_select VARCHAR2(1000);
q_where VARCHAR2(1000);
q_from VARCHAR2(5000);
q_query VARCHAR2(5000);
BEGIN
-- split cods string by comma
FOR i IN (
SELECT trim(regexp_substr(p_cod_str, '[^,]+', 1, LEVEL)) cod
FROM dual
CONNECT BY LEVEL <= regexp_count(p_cod_str, ',') + 1
) LOOP
q_loop := 'SELECT rownum as rn, a.id as id,
a.cod AS cod_a_' || i.cod || ', a.val AS val_a_' || i.cod || ',
b.cod AS cod_b_' || i.cod || ', b.val AS val_b_' || i.cod || '
FROM foo a, (
SELECT id, cod, val
FROM foo
WHERE dat = TO_DATE(''01-07-2019'', ''DD-MM-YYYY'')
) b
WHERE a.id = b.id AND a.cod = ' || i.cod || ' AND
a.dat = TO_DATE(''01-08-2019'', ''DD-MM-YYYY'')
';
q_select := q_select || ',
t_' || i.cod || '.cod_a_' || i.cod || ', t_' || i.cod || '.val_a_' || i.cod || ',
t_' || i.cod || '.cod_b_' || i.cod || ', t_' || i.cod || '.val_b_' || i.cod;
IF q_from IS NULL THEN
q_from := ' (
' || q_loop || '
) t_' || i.cod;
ELSE
q_from := q_from || '
FULL OUTER JOIN (
' || q_loop || '
) t_' || i.cod || '
ON t_' || i_prv || '.rn = t_' || i.cod || '.rn';
END IF;
i_prv := i.cod;
END LOOP;
-- mount query
q_query := 'SELECT ' || ltrim(q_select, ', ')
|| ' FROM ' || q_from;
dbms_output.put_line('query: ' || q_query);
END;
它将生成 SQL 并且 EXECUTE IMMEDIATE
我可以 运行 它。
结果:
COD_A_35|VAL_A_35|COD_B_35|VAL_B_35|COD_A_75|VAL_A_75|COD_B_75|VAL_B_75|COD_A_45|VAL_A_45|COD_B_45|VAL_B_45|
--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|
35| 38.5| 35| 58.1| 75| 74.65| 75| 69.32| 45| 3.89| 45| 38.5|
35| 69.32| 35| 102| 75| 32.8| 75| 74.65| | | | |
| | | | 75| 3.89| 75| 12.76| | | | |
感谢大家的提示
我是运行 Oracle 11g,需要将某些行分成列,但列数未确定,所以我需要动态地进行。
最初我想分成多个查询,然后再加入它们,但它似乎不是最合适的,而且我无法使其动态化。
这是我的 table:
的简化示例CREATE TABLE foo (
id NUMBER,
cod NUMBER,
val NUMBER,
dat DATE
);
INSERT INTO foo VALUES(1, 35, 58.10, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(2, 45, 38.50, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(3, 45, 3.89, TO_DATE('20-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(4, 35, 102.0, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(5, 75, 69.32, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(6, 75, 74.65, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(7, 45, 32.8, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(8, 75, 12.76, TO_DATE('01-07-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(1, 35, 38.50, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(2, 45, 3.89, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(3, 45, 102.0, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(4, 35, 69.32, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(5, 75, 74.65, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(6, 75, 32.8, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(7, 45, 38.50, TO_DATE('30-08-2019', 'DD-MM-YYYY'));
INSERT INTO foo VALUES(8, 75, 3.89, TO_DATE('01-08-2019', 'DD-MM-YYYY'));
SELECT a.cod, a.val, b.cod, b.val
FROM foo a, (
SELECT id, cod, val
FROM foo
WHERE dat = TO_DATE('01-07-2019', 'DD-MM-YYYY')
) b
WHERE a.id = b.id AND
a.dat = TO_DATE('01-08-2019', 'DD-MM-YYYY');
产量(按 COD 排序):
COD|VAL |COD|VAL |
---|-----|---|-----|
35| 38.5| 35| 58.1|
35|69.32| 35| 102|
45| 3.89| 45| 38.5|
75|74.65| 75|69.32|
75| 32.8| 75|74.65|
75| 3.89| 75|12.76|
我需要这些行只有一个不同的 COD,其他的将排列在新的列中。
预计:
COD 35 | COD 45 | COD 75 | <- illustrative
-------------------|-------------------|-------------------|
COD|VAL |COD|VAL |COD|VAL |COD|VAL |COD|VAL |COD|VAL |
---|-----|---|-----|---|-----|---|-----|---|-----|---|-----|
35| 38.5| 35| 58.1| 45| 3.89| 45| 38.5| 75|74.65| 75|69.32|
35|69.32| 35| 102| | | | | 75| 32.8| 75|74.65|
| | | | | | | | 75| 3.89| 75|12.76|
谢谢
我解决了以下问题:
DECLARE
p_cod_str VARCHAR2(100) := '35, 75, 45';
i_prv VARCHAR2(10);
q_loop VARCHAR2(1000);
q_select VARCHAR2(1000);
q_where VARCHAR2(1000);
q_from VARCHAR2(5000);
q_query VARCHAR2(5000);
BEGIN
-- split cods string by comma
FOR i IN (
SELECT trim(regexp_substr(p_cod_str, '[^,]+', 1, LEVEL)) cod
FROM dual
CONNECT BY LEVEL <= regexp_count(p_cod_str, ',') + 1
) LOOP
q_loop := 'SELECT rownum as rn, a.id as id,
a.cod AS cod_a_' || i.cod || ', a.val AS val_a_' || i.cod || ',
b.cod AS cod_b_' || i.cod || ', b.val AS val_b_' || i.cod || '
FROM foo a, (
SELECT id, cod, val
FROM foo
WHERE dat = TO_DATE(''01-07-2019'', ''DD-MM-YYYY'')
) b
WHERE a.id = b.id AND a.cod = ' || i.cod || ' AND
a.dat = TO_DATE(''01-08-2019'', ''DD-MM-YYYY'')
';
q_select := q_select || ',
t_' || i.cod || '.cod_a_' || i.cod || ', t_' || i.cod || '.val_a_' || i.cod || ',
t_' || i.cod || '.cod_b_' || i.cod || ', t_' || i.cod || '.val_b_' || i.cod;
IF q_from IS NULL THEN
q_from := ' (
' || q_loop || '
) t_' || i.cod;
ELSE
q_from := q_from || '
FULL OUTER JOIN (
' || q_loop || '
) t_' || i.cod || '
ON t_' || i_prv || '.rn = t_' || i.cod || '.rn';
END IF;
i_prv := i.cod;
END LOOP;
-- mount query
q_query := 'SELECT ' || ltrim(q_select, ', ')
|| ' FROM ' || q_from;
dbms_output.put_line('query: ' || q_query);
END;
它将生成 SQL 并且 EXECUTE IMMEDIATE
我可以 运行 它。
结果:
COD_A_35|VAL_A_35|COD_B_35|VAL_B_35|COD_A_75|VAL_A_75|COD_B_75|VAL_B_75|COD_A_45|VAL_A_45|COD_B_45|VAL_B_45|
--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|
35| 38.5| 35| 58.1| 75| 74.65| 75| 69.32| 45| 3.89| 45| 38.5|
35| 69.32| 35| 102| 75| 32.8| 75| 74.65| | | | |
| | | | 75| 3.89| 75| 12.76| | | | |
感谢大家的提示