我们有Oracle 12数据库。
我需要遍历表并根据前一行更新值。如下所示,我需要从第1行获取值并将其更新为第2行到第6行。然后从第7行获取新值并继续到表的末尾。 column1是csv格式的文本,所以我需要从那里提取数字值...
id column1 column2
1 xxx;yyy;zzz;123456;
2 aaa
3 bbb
4 ccc
5 ddd
6 eee
7 xxx;yyy;zzz;789123;
8 aaa
更新表后应如下所示:
id column1 column2
1 xxx;yyy;zzz;123456;
2 aaa 123456
3 bbb 123456
4 ccc 123456
5 ddd 123456
6 eee 123456
7 xxx;yyy;zzz;789123;
8 aaa 789123
Tbh我对pl / sql没有多少经验。 我尝试使用pl / sql while循环,但它没有工作。
如果有人能指引我正确的方向,那将是值得赞赏的。
答案 0 :(得分:1)
您不需要PL / SQL,可以使用MERGE
,LAG( ... ) IGNORE NULLS ...
分析函数和REGEXP_SUBSTR
的组合完全在SQL中完成(以提取子字符串):
MERGE INTO table_name dst
USING (
SELECT id,
CASE WHEN val IS NULL
THEN LAG( val ) IGNORE NULLS OVER ( ORDER BY id )
END AS val
FROM (
SELECT id,
REGEXP_SUBSTR( column1, ';(\d{6});$', 1, 1, NULL, 1 ) AS val
FROM table_name
)
) src
ON ( dst.id = src.id )
WHEN MATCHED THEN
UPDATE SET column2 = src.val;
更新的表格:
id column1 column2
-- ------------------- -------
1 xxx;yyy;zzz;123456;
2 aaa 123456
3 bbb 123456
4 ccc 123456
5 ddd 123456
6 eee 123456
7 xxx;yyy;zzz;789123;
8 aaa 789123
答案 1 :(得分:0)
这样的事情应该做你想要的。它循环遍历表格,每次以' xxx'开始时,将第一条记录的最后一位传递给变量。并更新第2列,如果它没有。
DECLARE
L_UpdateVal VARCHAR2(10) := '';
BEGIN
FOR REC IN (SELECT Column1, column2, ROWNUM From table) LOOP
IF SUBSTR(REC.column1, 1, 3) = 'xxx' THEN
L_UpdateVal := SUBSTR(column1, 13, 6);
ELSE
UPDATE Table SET Column2 = L_UpdateVal
WHERE ROWNUM := REC.ROWNUM
END IF;
END LOOP;
END;
答案 2 :(得分:0)
您不需要PL / SQL,您可以在单个MERGE语句中执行此操作。
首先,弄清楚如何获得你想要的结果 - 你可以通过使用'LAST_VALUE()'分析函数来实现这一点,如下所示:
WITH your_table AS (SELECT 1 id, 'xxx;yyy;zzz;123456;' column1, NULL column2 FROM dual UNION ALL
SELECT 2 id, 'aaa' column1, NULL column2 FROM dual UNION ALL
SELECT 3 id, 'bbb' column1, NULL column2 FROM dual UNION ALL
SELECT 4 id, 'ccc' column1, NULL column2 FROM dual UNION ALL
SELECT 5 id, 'ddd' column1, NULL column2 FROM dual UNION ALL
SELECT 6 id, 'eee' column1, NULL column2 FROM dual UNION ALL
SELECT 7 id, 'xxx;yyy;zzz;789123;' column1, NULL column2 FROM dual UNION ALL
SELECT 8 id, 'aaa' column1, NULL column2 FROM dual)
select id,
column1,
last_value(CASE WHEN substr(column1, -1) = ';' THEN
regexp_substr(column1, ';*([[:digit:]]*)(;$)', 1, 1, NULL, 1)
END IGNORE NULLS) OVER (ORDER BY ID) column2
from your_table;
ID COLUMN1 COLUMN2
---------- ------------------- -------------------
1 xxx;yyy;zzz;123456; 123456
2 aaa 123456
3 bbb 123456
4 ccc 123456
5 ddd 123456
6 eee 123456
7 xxx;yyy;zzz;789123; 789123
8 aaa 789123
然后您可以在MERGE语句中使用它来执行更新,如下所示:
MERGE INTO your_table tgt
USING (select id,
column1,
CASE WHEN substr(column1, -1) = ';' THEN 'Y' ELSE 'N' END driving_column1,
last_value(CASE WHEN substr(column1, -1) = ';' THEN
regexp_substr(column1, ';*([[:digit:]]*)(;$)', 1, 1, NULL, 1)
END IGNORE NULLS) OVER (ORDER BY ID) column2 -- assuming id drives the correct order to use here
from your_table) src
ON (tgt.id = src.id) -- assuming id is the primary key of your_table
WHEN MATCHED THEN
UPDATE SET tgt.column2 = src.column2;
如果您不想更新其中值为csv值的column1行的column2(我假设如果它们是csv值,则会出现分号),那么您可以更新ON包含and driving_column1 = 'N'
的子句,或者您可以将源子查询包装在一个外部查询中,该查询在drivers_column1上进行过滤(不幸的是,您无法在同一查询中过滤分析函数),或者您可以在更新中添加where子句合并声明的一部分。