带有在子查询中生成的值的 Oracle SQL 更新语句

Posted

技术标签:

【中文标题】带有在子查询中生成的值的 Oracle SQL 更新语句【英文标题】:Oracle SQL Update statement with value generated in subquery 【发布时间】:2020-01-14 17:34:08 【问题描述】:

我正在尝试编写一个更新语句来插入在子查询中计算的值,但成功率有限。

到目前为止我尝试过的语句是:

update intuit.men_doc doc1
set doc1.doc_udf5 = (select
substr(doc.doc_dtyc, instr(doc.doc_dtyc, 'GAPP-', 2)+5 )||'_'||row_number() over(partition by 
doc.doc_dtyc order by doc.doc_cret) docDeleteId
from
intuit.men_doc doc 
where
doc.doc_dtyc != 'DM-GAPP-SFUL'
and doc.doc_dtyc like 'DM-GAPP%'
and doc.doc_cred >= '01/Oct/2017' and doc.doc_cred < '01/Oct/2018'
and doc1.doc_code = doc.doc_code
)

这给了我以下错误信息

ERROR: Error 1427 was encountered whilst running the SQL command. (-3)
Error -3 running SQL : ORA-01427: single-row subquery returns more than one row

我对 UPDATE 语句没有太多经验,因此如果我能提供任何关于如何重写它以便一次更新几千条记录的建议,我将不胜感激。

编辑:添加示例数据

示例数据:

MEN_DOC
DOC_CODE    DOC_DTYC    DOC_UDF5    DOC_CRED
123456A     CV                      08/Nov/2017
456789B     CV                      11/Jan/2018
789123C     CV                      15/Feb/2018
123987B     TRAN                    01/Dec/2017             

脚本运行后我希望数据如何显示

MEN_DOC
DOC_CODE    DOC_DTYC    DOC_UDF5    DOC_CRED
123456A     CV          CV_1        08/Nov/2017
456789B     CV          CV_2        11/Jan/2018
789123C     CV          CV_3        15/Feb/2018
123987B     TRAN        TRAN_1      01/Dec/2017  

谢谢

【问题讨论】:

LIMIT 1(和ORDER BY)添加到子查询中,例如... 您的 select 语句返回的匹配记录超过 1 条,因此它不知道要更新的值是什么。独立运行您的 select 语句并确保它只返回 1 条匹配的记录。 具有预期结果的样本数据会有所帮助。您想单独更新每一行还是应该让子查询从几行计算新值? 已更新示例数据 是否有可能有多个 DOC_CODE 用于指定条件? 【参考方案1】:

您正在使用row_number(),这表明您希望子查询返回多于一行。 doc_code 上的不等式支持这种解释。

只需将row_number() 更改为count(*),这样您就有了一个始终返回一行并获得您想要的顺序计数的聚合:

update intuit.men_doc doc1
    set doc1.doc_udf5 = (select substr(doc.doc_dtyc, instr(doc.doc_dtyc, 'GAPP-', 2)+5 ) ||'_'|| count(*) docDeleteId
                         from intuit.men_doc doc 
                         where doc.doc_dtyc <> 'DM-GAPP-SFUL' and
                               doc.doc_dtyc like 'DM-GAPP%' and
                               doc.doc_cred >= date '2017-10-01' and
                               doc.doc_cred < date '2018-10-01' and
                               doc1.doc_code = doc.doc_code
                         );

【讨论】:

谢谢你。不确定我是否解释了我想要做得足够好。我在 men_doc 表中有数千条记录,其中 doc_dtyc 中的值有几个不同的选项。我想在由 doc_dtyc 分区的 doc_udf5 中存储一个唯一的序列号。例如,其中 DOC_DTYC = 'CV',DOC_UDF5 = 'CV_1',然后是 'CV_2' 用于下一条记录,依此类推...【参考方案2】:

您可以使用您的select 作为merge 中的源表,如下所示:

merge into men_doc tgt
using (select doc_code, 
              doc_dtyc||'_'||row_number() over (partition by doc_dtyc order by doc_cred) as calc
         from men_doc) src
on (tgt.doc_code = src.doc_code)
when matched then update set tgt.doc_udf5 = src.calc;

dbfiddle

我假设 doc_code 是唯一的。

【讨论】:

以上是关于带有在子查询中生成的值的 Oracle SQL 更新语句的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Oracle SQL Developer 中生成带有子查询的 INSERT 语句?

优化实体框架中生成的sql查询?

oracle 10G数据库如何插入clob字段的值的简单语句sql语句

oracle语句,我想查询A表中的a字段下的值不等于B表中b的值的数据,

在子查询中为数据透视列的值实现 WHERE 子句?

提示 oracle 在子查询上使用索引——Oracle SQl