更新一行以基于另一行的转换 (Oracle)
Posted
技术标签:
【中文标题】更新一行以基于另一行的转换 (Oracle)【英文标题】:Updating a row to be based on a transformation of another row (Oracle) 【发布时间】:2019-07-04 10:53:38 【问题描述】:我有一张有几行 (~100) 行的表格。其中一列基本上是以逗号分隔的字符串列表,可能包含也可能不包含空格。现在我需要另一列是该列的转换:删除空格,用逗号分隔,按字母顺序排序并再次用逗号连接。
我有以下适用于一行的 SQL(所有其他行都获得相同的值),但我不知道如何让它在整个表上工作。我可能错过了一个地方,但似乎无法正确:
update client set sorted = (select listagg(somedata, ',')
within group (order by somedata) somedata from (
with q as (select ','||regexp_replace(unsorted, '\s+', '') as somedata
from client)
select regexp_substr(somedata, ',([^,]+)',1,rownum,'i',1) somedata
from q,
(select 1 from q connect by level <= length(regexp_replace(somedata, '[^,]', '')))
));
我错过了什么? 谢谢。
【问题讨论】:
这是一个糟糕的方法。当存储逗号分隔值本身是一种不好的做法时,与其拥有另一列存储具有排序值的基本相同的东西是没有意义的。相反,您必须考虑通过将单个值存储为行来将它们转换为另一个表,可能与父表中的相同键 我知道,但是当我们最初开发应用程序时,我们必须将其视为单个字符串,逗号分隔对我们来说毫无意义。不过现在情况发生了变化,但切换整个结构是不可行的。 正如我经常告诉 OP 此类问题的那样,现在 或永远不会。 ..或者设计会在未来的岁月里受到伤害。 虽然您可能是正确的,但我需要在一列中排序字符串,因为我确实需要基于排序的列运行相当快的选择。 【参考方案1】:使用相关子查询:
Oracle 设置:
CREATE TABLE client ( unsorted, sorted ) AS
SELECT 'b , c ,e f, d, a', CAST( NULL AS VARCHAR2(30) ) FROM DUAL UNION ALL
SELECT 'z , y, x,w,v ,u', CAST( NULL AS VARCHAR2(30) ) FROM DUAL;
更新:
UPDATE client c
SET sorted = (
SELECT LISTAGG(
REGEXP_REPLACE( REGEXP_SUBSTR( c.unsorted, '[^,]+', 1, LEVEL ), '\s+' ),
','
) WITHIN GROUP (
ORDER BY REGEXP_REPLACE( REGEXP_SUBSTR( c.unsorted, '[^,]+', 1, LEVEL ), '\s+' )
)
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( c.unsorted, ',' ) + 1
)
输出:
SELECT * FROM client;
未分类 |已排序
:---------------- | :----------
b, c, e f, d, a | a,b,c,d,ef
z , y, x,w,v ,u | u,v,w,x,y,z
db小提琴here
【讨论】:
以上是关于更新一行以基于另一行的转换 (Oracle)的主要内容,如果未能解决你的问题,请参考以下文章
oracle更新一行数据,另一个会话读取是为啥会产生2个CR块?