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