【问题标题】:How to prevent duplicate entry key when update更新时如何防止重复输入键
【发布时间】:2021-05-25 12:08:56
【问题描述】:

问题说明

我不会更新 3 个主键连接的最后一个主键。但问题有时是多个记录的第一个和第二个主键相同。在这种情况下,当我设置我的新值时,即使我使用子请求来避免这个问题,我也会有一个重复的条目键。

一些代码

架构

create table llx_element_contact
(
    rowid             int auto_increment
        primary key,
    datecreate        datetime           null,
    statut            smallint default 5 null,
    element_id        int                not null,
    fk_c_type_contact int                not null,
    fk_socpeople      int                not null,
    constraint idx_element_contact_idx1
        unique (element_id, fk_c_type_contact, fk_socpeople)
)

更新请求

此请求返回重复键错误

update llx_element_contact lec
set lec.fk_socpeople = 64
where 
-- Try to avoid the error by non including the values that are the same
(select count(*)
 from llx_element_contact ec
 where ec.fk_socpeople = 64
   and ec.element_id = lec.element_id
   and ec.fk_c_type_contact = lec.fk_c_type_contact) = 0

测试数据

rowid, datecreate, statut, element_id, fk_c_type_contact, fk_sockpeople
65,2015-08-31 18:59:18,4,65,160,30
66,2015-08-31 18:59:18,4,66,159,12
67,2015-08-31 18:59:18,4,67,160,12
15283,2016-03-23 11:47:15,4,6404,160,39
15284,2016-03-23 11:51:30,4,6404,160,58

【问题讨论】:

  • “dup 错误”问题是数据示例中的最后 2 行。更新后两者都会有(element_id, fk_c_type_contact, fk_socpeople) = (6404,160,64),但这个组合被定义为唯一。您是唯一可以说出在这种情况下必须执行的操作的人。其中一行(究竟是什么?)必须保持不变?别的东西?这不是SQL代码的问题,是缺少算法的问题。而且必须从代码中解决。
  • 根据查询过滤表中相同字段 = 64 的元素将字段更新为 64 是否有意义?
  • @Akina 我想根据最近的日期更改第一个
  • @JaimeDrq 我没有包含我的过滤器,因为这不是这个问题的目的,但当然在我的实际数据库中我有一些条件可以做到这一点:)

标签: mysql sql mariadb


【解决方案1】:

当您尝试将相同的值分配给 3d 成员时,您应该只检查唯一约束的其他两个成员。最多只能存在一行具有相同的两个成员。

update llx_element_contact lec
set lec.fk_socpeople = 64
where 
-- Try to avoid the error by non including the values that are the same
(select count(*)
 from llx_element_contact ec
 where ec.element_id = lec.element_id
   and ec.fk_c_type_contact = lec.fk_c_type_contact) <=1

update llx_element_contact lec
set lec.fk_socpeople = 64
where 
-- Try to avoid the error by non including the values that are the same
 not exists (select 1
 from llx_element_contact ec
 where ec.element_id = lec.element_id
   and ec.fk_c_type_contact = lec.fk_c_type_contact
   and lec.fk_socpeople != ec.fk_socpeople)

【讨论】:

  • 'You can't specify target table 'lec' for update in FROM clause' 两种变体
  • @Akina 我没有找到问题
  • @MrSolarius precise 服务器版本是什么?一些 MariaDB,10.3 或更高版本?
【解决方案2】:

你可以使用:

您可以使用left join 检查相应的行是否不存在,以防止unique 冲突:

update llx_element_contact lec left join
       (select element_id, fk_c_type_contact
        from llx_element_contact lec2
        where lec2.fk_socpeople = 64
        group by element_id, fk_c_type_contact
       ) lec2
       using (element_id, fk_c_type_contact)
    set lec.fk_socpeople = 64
    where lec2.element_id is null;

您的查询中有未解释的附加逻辑。对于您的要求,这不是必需的。

【讨论】:

  • 感谢您的快速答复,但是当我在我的数据库中尝试您的请求时,我仍然遇到重复输入错误。使用此数据:15409,2016-03-24 11:19:46,4,7122,160,61 15407,2016-03-24 11:04:50,4,7122,160,62
  • @MrSolarius 。 . .您不能有重复的条目。有一个唯一的约束。
【解决方案3】:
WITH cte AS (
SELECT rowid, 
       SUM(fk_socpeople = 64) OVER (PARTITION BY element_id, fk_c_type_contact) u_flag,
       ROW_NUMBER() OVER (PARTITION BY element_id, fk_c_type_contact ORDER BY datecreate DESC) u_rn
FROM llx_element_contact
)
update llx_element_contact lec
JOIN cte USING (rowid)
set lec.fk_socpeople = 64 
where cte.u_flag = 0
  AND cte.u_rn = 1

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=08e20328ccc6187716084ce9d78816b0

【讨论】:

  • 感谢您在 dbfiddle 向我介绍我不知道,这真的很酷 :) 您的要求也适用于我 =D
  • @MrSolarius 有很多关于 DBMS、编程语言、正则表达式的在线小提琴......
猜你喜欢
  • 2011-06-12
  • 2015-08-30
  • 2012-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多