如何在pl/sql中循环表和更新值

如何在pl/sql中循环表和更新值,sql,oracle,loops,plsql,Sql,Oracle,Loops,Plsql,我们有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

我们有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循环,但没有成功


如果有人能把我踢向正确的方向,我将不胜感激。

您不需要PL/SQL来实现这一点,它可以完全在SQL中使用合并、延迟。。。忽略空值。。。用于提取子字符串的分析函数和REGEXP_SUBSTR:

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

像这样的东西可以满足你的需要。它在表中循环,每次以“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;

这不需要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 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;
然后您可以在MERGE语句中使用它来执行更新,如下所示:

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 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;

如果您不想更新column1行的column2,其中的值是csv值,我假设如果它们是csv值,则会出现分号,然后,您可以将ON子句更新为include and driving_column1='N',也可以将源子查询包装在一个外部查询中,该查询在driving_column1上进行过滤。很遗憾,您不能在同一查询中对分析函数进行过滤,或者您可以将where子句添加到merge语句的update部分。

一些快速查询。行是否总是以六行为一组,或者可以变化,并且第一行是否总是相同的长度?否行可以从24行变化到更多行。第一行的长度都是一样的,前三个字母也是一样的。我可以使用这个代码,只需稍加调整。最后一个合并部分缺少“src”和“set”命令,但在我添加这些命令之后,一切都很好。@snow是的,对此表示歉意;我一定是太兴奋了,没有仔细检查我写的东西。哦!