我正在寻找一种将多行“合并”为单个行的想法
让我说我有这样的桌子:
ID | A | B | C | D |
____________________________
1 | x | y |null | z |
2 |null | z |null | x |
3 | p | w | a |null |
4 | o |null | k |null |
现在,我需要将ID较低的所有行的更改应用于每行。 第一行是基础,因此它应该看起来像:
1 | x | y |null | z |
现在,对于第二行,我需要采用第一行并从第二行开始应用更改(如果列不为null)。第二行应如下所示:
2 | x | z |null | x |
第三行-占据第一行,从第二行到第三行应用更改:
3 | p | w | a | x |
第四行-占据第一行,应用第二,第三和第四行的更改:
4 | o | w | k | x |
所以输出应如下所示:
1 | x | y |null | z |
2 | x | z |null | x |
3 | p | w | a | x |
4 | o | w | k | x |
是否可以使用任何Oracle功能?
答案 0 :(得分:6)
您可以通过ignore nulls
选项使用the last_value()
function:
last_value(a) ignore nulls over (order by id)
将为您提供在a
列中看到的最后一个非空值,直到当前ID(使用默认窗口);因此您可以为要“合并”的每一列重复该操作:
select id,
last_value(a) ignore nulls over (order by id) as a,
last_value(b) ignore nulls over (order by id) as b,
last_value(c) ignore nulls over (order by id) as c,
last_value(d) ignore nulls over (order by id) as d
from your_table
order by id;
将您的示例数据作为CTE:
with your_table (id, a, b, c, d) as (
select 1, 'x', 'y', null, 'z' from dual
union all select 2, null, 'z', null,'x' from dual
union all select 3, 'p', 'w', 'a', null from dual
union all select 4, 'o', null, 'k', null from dual
)
select id,
last_value(a) ignore nulls over (order by id) as a,
last_value(b) ignore nulls over (order by id) as b,
last_value(c) ignore nulls over (order by id) as c,
last_value(d) ignore nulls over (order by id) as d
from your_table
order by id;
ID A B C D
---------- - - - -
1 x y z
2 x z x
3 p w a x
4 o w k x
答案 1 :(得分:5)
使用分层查询:
CREATE TABLE abcd(
id int,
A varchar2(10),
B varchar2(10),
C varchar2(10), D varchar2(10)
);
insert all
into abcd values(1,'x','y',null,'z')
into abcd values(2,null,'z',null,'x')
into abcd values(3,'p','w','a',null)
into abcd values(4,'o',null,'k',null)
select 1 from dual;
commit;
WITH qq(id, a,b,c,d) AS(
SELECT id, a,b,c,d FROM abcd WHERE id = 1
UNION ALL
SELECT x.id,
coalesce( x.a, qq.a ),
coalesce( x.b, qq.b ),
coalesce( x.c, qq.c ),
coalesce( x.d, qq.d )
FROM qq
JOIN abcd x ON x.id = qq.id + 1
)
SELECT * FROM qq;
ID A B C D
---------- ---------- ---------- ---------- ----------
1 x y z
2 x z x
3 p w a x
4 o w k x
答案 2 :(得分:1)
类似于LAST_VALUE
,您还可以使用COALESCE
和LAG
。
Oracle设置:
一个小的PL / SQL脚本,用于创建具有预定义列数的表,并用10行随机数据填充该表,该数据有50%的机会是NULL
。
--DROP TABLE table_name;
--DROP SEQUENCE table_name_seq;
SET SERVEROUTPUT ON;
DECLARE
num_columns INT := 5;
ct CLOB := 'CREATE TABLE table_name ( id INT';
ins CLOB := 'INSERT INTO table_name VALUES ( table_name_seq.nextval';
val CLOB := 'SELECT id';
BEGIN
FOR i IN 1 .. num_columns LOOP
ct := ct || ', c' || TO_CHAR( i, 'FM00' ) || ' INT';
ins := ins || ',' || CHR(10) || ' CASE WHEN DBMS_RANDOM.VALUE < .5 THEN NULL ELSE TRUNC( DBMS_RANDOM.VALUE( 0, 100 ) ) END';
val := val || ',' || CHR(10) || ' COALESCE( c' || TO_CHAR( i, 'FM00' ) || ', LAG( c' || TO_CHAR( i, 'FM00' ) || ' ) IGNORE NULLS OVER ( ORDER BY id ) ) AS c' || TO_CHAR( i, 'FM00' );
END LOOP;
ct := ct || ' )';
ins := ins || ' )';
val := val || CHR(10) || 'FROM table_name;';
EXECUTE IMMEDIATE ct;
EXECUTE IMMEDIATE 'CREATE SEQUENCE table_name_seq';
FOR i IN 1 .. 10 LOOP
EXECUTE IMMEDIATE ins;
END LOOP;
DBMS_OUTPUT.PUT_LINE( val );
END;
/
查询1 :
SELECT * FROM table_name;
结果:
ID C01 C02 C03 C04 C05
---------- ---------- ---------- ---------- ---------- ----------
1
2 37 82 85 21
3 8 76 55
4 98 66 78
5 17 39 19
6 17 3 91
7 76 42 63 19
8 18 95
9 88 24 49
10 51 81 49
查询2 :
SELECT id,
COALESCE( c01, LAG( c01 ) IGNORE NULLS OVER ( ORDER BY id ) ) AS c01,
COALESCE( c02, LAG( c02 ) IGNORE NULLS OVER ( ORDER BY id ) ) AS c02,
COALESCE( c03, LAG( c03 ) IGNORE NULLS OVER ( ORDER BY id ) ) AS c03,
COALESCE( c04, LAG( c04 ) IGNORE NULLS OVER ( ORDER BY id ) ) AS c04,
COALESCE( c05, LAG( c05 ) IGNORE NULLS OVER ( ORDER BY id ) ) AS c05
FROM table_name;
结果:
ID C01 C02 C03 C04 C05
---------- ---------- ---------- ---------- ---------- ----------
1
2 37 82 85 21
3 8 82 85 76 55
4 98 82 66 78 55
5 17 82 39 78 19
6 17 3 91 78 19
7 76 3 42 63 19
8 18 3 95 63 19
9 88 24 49 63 19
10 88 51 49 81 49
将num_columns
的值更改为99,可以看到它在具有100个值的表上正常工作。