Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何仅从列中选取一组特定的值,并基于该值生成update语句_Sql_Plsql_Oracle11g - Fatal编程技术网

Sql 如何仅从列中选取一组特定的值,并基于该值生成update语句

Sql 如何仅从列中选取一组特定的值,并基于该值生成update语句,sql,plsql,oracle11g,Sql,Plsql,Oracle11g,我是PL/SQL新手,面临以下场景 我有一个问题,需要基于列值运行一组update语句 因此,我们将在select查询之后获得一组如下所示的ID ------------------------------------- ID ChangedColumns ChangedValues ------------------------------------- 101 col1|col2| [A^B]|[123^456]| 102 col3|

我是PL/SQL新手,面临以下场景

我有一个问题,需要基于列值运行一组update语句

因此,我们将在select查询之后获得一组如下所示的ID

-------------------------------------
ID   ChangedColumns     ChangedValues         
-------------------------------------
101     col1|col2|    [A^B]|[123^456]|
102      col3|        [XXX^YYY]|
...     ....      ....

and so on
其中ChangedColumns是已更改的列名,ChangedValues将告知由管道“|”分隔并用大括号“[]”括起的各个列的新旧值

基于此,我需要在另一个表上运行update语句,类似于

update table
set col1='A',
col2='123'
where id = 101;

update table
set col3='XXX'
where id = 102;

update table
.....
..... and so on
更改的列数可以是1-20,其相应的更改值在ChangedValues列中的顺序相同

有人能告诉我如何为同样的代码编写PL/SQL块吗


非常感谢

首先,我按ID和ChangedColumn对数据进行了分解:

UPDATE table2 
SET table2.col1 = table1.col1, 
table2.col2 = table1.col2,
...
FROM table1, table2 
WHERE table1.memberid = table2.memberid
SQL> with tbl(ID, ChangedColumns, ChangedValues) as (
     select 101, 'col1|col2|', '[A^B]|[123^456]|' from dual
     union
     select 102, 'col3|', '[XXX^YYY]|' from dual
   )
   SELECT ID,
          REGEXP_SUBSTR(ChangedColumns ,'([^|]*)(\|)', 1, COLUMN_VALUE, NULL, 1 ) as changedcolumn,
          REGEXP_SUBSTR(ChangedValues ,'([^|]*)(\|)', 1, COLUMN_VALUE, NULL, 1 ) as column_value
        FROM   tbl,
               TABLE(
                 CAST(
                   MULTISET(
                     SELECT LEVEL
                     FROM   DUAL
                     CONNECT BY LEVEL <= REGEXP_COUNT( ChangedColumns ,'\|' )
                   ) AS SYS.ODCINUMBERLIST
                 )
               );

        ID CHANGEDCOL COLUMN_VALUE
---------- ---------- ----------------
       101 col1       [A^B]
       101 col2       [123^456]
       102 col3       [XXX^YYY]

SQL>
然后将其更改为为为每个ID更改的每个列生成单独的update语句。下一步是将其转换为每个ID的一个update语句,处理所有更改的列:

SQL> with tbl(ID, ChangedColumns, ChangedValues) as (
     select 101, 'col1|col2|', '[A^B]|[123^456]|' from dual
     union
     select 102, 'col3|', '[XXX^YYY]|' from dual
   )
   SELECT 'update table set ' ||
          REGEXP_SUBSTR(ChangedColumns, '([^|]*)(\|)', 1, COLUMN_VALUE, NULL, 1 ) ||
          ' = ''' ||
          REGEXP_SUBSTR(ChangedValues, '\[([^\^]*)(\^)', 1, COLUMN_VALUE, NULL, 1 ) ||
          '''' ||
          ' where id = ' || id || ';' as update_stmt
        FROM   tbl,
               TABLE(
                 CAST(
                   MULTISET(
                     SELECT LEVEL
                     FROM   DUAL
                     CONNECT BY LEVEL <= REGEXP_COUNT( ChangedColumns ,'\|' )
                   ) AS SYS.ODCINUMBERLIST
                 )
               );

UPDATE_STMT
--------------------------------------------------------------------------------
update table set col1 = 'A' where id = 101;
update table set col2 = '123' where id = 101;
update table set col3 = 'XXX' where id = 102;

SQL>
编辑:以下是经过进一步细化和调整后的最终产品:

SQL> with tbl_a(ID, ChangedColumns, ChangedValues) as (
    select 101, 'col1|col2|', '[A^B]|[123^456]|' from dual
    union
    select 102, 'col3|', '[XXX^YYY]|' from dual
    union
    select 103, 'col4|col5|col6|col7|col8|', '[XX0^YY0]|[XX1^YY1]|[XX2^YY2]|[XX3^YY3]|[XX4^YY4]|' from dual
  ),
  tbl_b(ID, column_value) as (
  SELECT ID,
         REGEXP_SUBSTR(ChangedColumns ,'([^|]*)(\|)', 1, COLUMN_VALUE, NULL, 1 ) ||
         ' = ' || CHR(39) ||
         REGEXP_SUBSTR(ChangedValues ,'\[([^\^]*)(\^)', 1, COLUMN_VALUE, NULL, 1 ) || CHR(39)
       FROM   tbl_a,
              TABLE(
                CAST(
                  MULTISET(
                    SELECT LEVEL
                    FROM   DUAL
                    CONNECT BY LEVEL <= REGEXP_COUNT( ChangedColumns ,'\|' )
                  ) AS SYS.ODCINUMBERLIST
                )
              )
  )
  SELECT distinct ID,
     'UPDATE TABLE SET ' || LISTAGG(column_value, ', ')
      WITHIN GROUP (ORDER BY id, column_value)
      OVER (PARTITION BY id) || ' WHERE ID = ' || ID || ';' as update_stmt
  FROM tbl_b
  ORDER BY ID;

       ID UPDATE_STMT
--------- ------------------------------------------------------------------------------------------------------
      101 UPDATE TABLE SET col1 = 'A', col2 = '123' WHERE ID = 101;
      102 UPDATE TABLE SET col3 = 'XXX' WHERE ID = 102;
      103 UPDATE TABLE SET col4 = 'XX0', col5 = 'XX1', col6 = 'XX2', col7 = 'XX3', col8 = 'XX4' WHERE ID = 103;

SQL>

我想这可以进一步简化,但有一点可以说,就是把问题分解成更小的步骤。

你好,Sarikaya,谢谢你的回答,但这不是我想要的。101的第一个update语句应该设置从ChangedValues列中选取的col1和col2值。第二个update语句应该更新从相应的changed values列派生的col3值。返回的ID数和更改的列数每天都会增加。我知道我们应该使用一些游标/循环和substr/instr函数,但不确定具体如何使用。谢谢你,加里,非常感谢。这正是我想要的。你让我开心,酷!如果这对你有用,请接受它,这样将来的搜索者就会知道什么是有用的。最终的查询就像一个符咒。最初我没有注意到一些changedValue为NULL。因此,更新无法正常工作。为了克服这个问题,我在listag函数中做了如下更改更新表集“| | LISTAGGreplacecolumn_值,'NULL',','。。我刚刚接受了答案,但我不知道怎么做,所以谷歌搜索了一遍,再次感谢你的回复。通过这个答案,我至少学会了Oracle中的4个新功能。我更新了我的帖子,给出了一个更精确的答案。