根据选择查询更新记录

Posted

技术标签:

【中文标题】根据选择查询更新记录【英文标题】:Update records based on select query 【发布时间】:2019-06-16 20:58:26 【问题描述】:

我有一张桌子1:

u_a_id  d_c_s   c_nm    c_seq   r_c_p
1       908     Test1   1       20
10      908     Test1   1       21
11      908     Test1   1       12
12759   908     Test1   1       31
12759   908     Test1   1       32
12861   878     Test2   1       43
12861   878     Test2   1       44

我还有一张桌子2:

d_c_s   c_nm    c_seq   n_min_d_c_s     n_min_c_nm
908     Test1   1       12001           Test1, First
878     Test2   1       12002           Test2, First

我需要更新table1 ==>

table1.c_nm = table2.n_min_c_nm table1.d_c_s = table2.n_min_d_c_s

要更新的条件是:

仅记录 (u_a_id, d_c_s, c_seq) > 1 -- select u_a_id, d_c_s, c_nm, c_seq, count(*) cnt from table1 where c_nm not in ('VOID', 'WRONG') group by u_a_id, d_c_s, c_nm, c_seq having count(*) > 1; table1.d_c_s = table2.d_c_s table1.c_nm = table2.c_nm table1.c_seq = table2.c_seq 使用 r_c_p 的最小值

输出如下:

u_a_id  d_c_s   c_nm            c_seq   r_c_p
1       908     Test1           1       20
10      908     Test1           1       21
11      908     Test1           1       12
12759   12001   Test1, First    1       31
12759   908     Test1           1       32
12861   12002   Test2, First    1       43
12861   878     Test2           1       44

创建 UPDATE/MERGE 查询以实现这一点的最佳方法是什么?

DBFIDDLE 演示 - Link

【问题讨论】:

【参考方案1】:

您可以使用MERGE 语句与以下内容相同:

MERGE INTO TABLE1 T1 
USING (
       SELECT
           MIN(TI1.R_C_P) AS R_C_P,
           TI1.U_A_ID,
           TI1.D_C_S,
           TI1.C_NM,
           TI1.C_SEQ,
           TI2.N_MIN_C_NM,
           TI2.N_MIN_D_C_S
       FROM
           TABLE1 TI1
           JOIN TABLE2 TI2 
           ON ( TI1.D_C_S = TI2.D_C_S
                AND TI1.C_NM = TI2.C_NM
                AND TI1.C_SEQ = TI2.C_SEQ
                AND TI1.C_NM NOT IN (
               'VOID',
               'WRONG'
           ) )
       GROUP BY
           TI1.U_A_ID,
           TI1.D_C_S,
           TI1.C_NM,
           TI1.C_SEQ,
           TI2.N_MIN_C_NM,
           TI2.N_MIN_D_C_S
       HAVING
           COUNT(1) > 1
   )
T2 ON ( T1.C_SEQ = T2.C_SEQ
        AND T1.R_C_P = T2.R_C_P )
WHEN MATCHED THEN 
UPDATE 
SET T1.C_NM = T2.N_MIN_C_NM,
T1.D_C_S = T2.N_MIN_D_C_S
WHERE
    T1.D_C_S = T2.D_C_S
    AND T1.C_NM = T2.C_NM 
    AND T1.U_A_ID = T2.U_A_ID -- ADDED THIS CONDITION
-- WHERE CONDITION IS USED AS IT CAN NOT BE USED INSIDE ON CLAUSE
-- TO AVOID ERROR : ORA-38104: Columns referenced in the ON Clause cannot be updated

Demo DB Fiddler

干杯!!

【讨论】:

如果我将第一行的 R_C_P 更改为 43,则会给出错误的输出 -- dbfiddle.uk/… 是的,我试图在 WHERE 子句中放置一些独特的列。现在我将U_A_ID 放入其中,以便它可以识别正确的记录。如果 Table1 有 PK 则仅在 WHERE 子句中使用该列。请查看更新后的答案和更新的提琴手链接 这条线——T2 ON(T2.C_SEQ = T2.C_SEQ——正确吗? 哦.. 不,那不正确。现已更正。 会不会因此而引起任何问题?【参考方案2】:
UPDATE table1 t1
SET t1.d_c_s =
(select 
t2.n_min_d_c_s
from
table2 t2
WHERE t1.d_c_s=t2.d_c_s
AND t1.c_nm=t2.c_nm
AND t1.c_seq=t2.c_seq),
t1.c_nm = 
(select 
t2.n_min_c_nm
from
table2 t2
WHERE t1.d_c_s=t2.d_c_s
AND t1.c_nm=t2.c_nm
AND t1.c_seq=t2.c_seq)

WHERE t1.r_c_p in (
SELECT min(r_c_p) min_r_c_p 
from table1
where c_nm not in ('VOID', 'WRONG') 
group by u_a_id, d_c_s, c_nm, c_seq 
having count(*) > 1
);

https://dbfiddle.uk/?rdbms=oracle_18&fiddle=870bca3d3cfb72e4638f678b9bf05199

【讨论】:

如果我将第一行的 r_c_p 更改为 43,则会给出错误的输出 - dbfiddle.uk/… 不清楚这是一项要求。看起来你找到了一个满足你需求的答案,所以我不会重做这个。

以上是关于根据选择查询更新记录的主要内容,如果未能解决你的问题,请参考以下文章

更新查询更新所有记录 - 只希望选择记录更新

访问选择查询记录集不可更新

根据下拉选择自动更新表单中显示的查询

PLSQL 触发器 - 基于选择查询更新记录

09 | 普通索引和唯一索引,应该怎么选择?

复杂Rails Active Record查询选择具有真实结果的记录,以便当天最新更新其他创建的记录