【问题标题】:Getting error "duplicate key value violates unique constraint postgres"收到错误“重复键值违反唯一约束 postgres”
【发布时间】:2021-04-10 04:23:24
【问题描述】:

我有这样的表:

p_id | store |      createdat      | device  | deviceserial | application
------+-------+---------------------+---------+--------------+-------------
      | z10   | 2020-09-02 08:02:39 | Android | 636363636890 | app-a
      | z10   | 2020-09-02 08:08:18 | Android | 636363636890 | app-a
      | z10   | 2020-09-02 08:10:10 | Android | 636363636890 | app-a
      | z10   | 2020-09-02 08:20:10 | Android | 636363636890 | app-a
      | z10   | 2020-09-02 10:40:11 | IOS     | 6625839827   | app-b
      | z10   | 2020-09-02 10:45:11 | IOS     | 6625839827   | app-b
      | z10   | 2020-09-02 10:50:11 | IOS     | 6625839827   | app-b
      | z11   | 2020-09-02 08:47:10 | Android | 636363636891 | app-a
      | z11   | 2020-09-02 08:55:10 | Android | 636363636891 | app-a
      | z11   | 2020-09-02 08:59:10 | Android | 636363636891 | app-a
      | z11   | 2020-09-02 13:01:11 | IOS     | 6625839828   | app-b
      | z11   | 2020-09-02 13:15:11 | IOS     | 6625839828   | app-b
      | z10   | 2020-09-02 12:03:10 | Android | 636363636890 | app-a
      | z10   | 2020-09-02 12:09:10 | Android | 636363636890 | app-a
      | z10   | 2020-09-02 12:12:10 | Android | 636363636890 | app-a
      | z10   | 2020-09-02 15:15:11 | IOS     | 6625839827   | app-b
      | z10   | 2020-09-02 15:20:11 | IOS     | 6625839827   | app-b
      | z11   | 2020-09-02 10:25:10 | Android | 636363636891 | app-a
      | z11   | 2020-09-02 10:35:10 | Android | 636363636891 | app-a

我正在尝试向另一个表(device_usage_test1)插入一些查询。那是我的表:

create table if not exists device_usage_test1(id SERIAL,deviceserial VARCHAR(50) UNIQUE,device VARCHAR(50),deviceusage DOUBLE PRECISION)

这是我的插入命令:

insert into device_usage_test1(deviceserial,device,deviceusage) select deviceserial,device,sum(deviceusage) as deviceusage
from (
    select deviceserial,device,
         
     extract(epoch from (max(createdat)::timestamp - min(createdat)::timestamp)) as deviceusage,
     date_trunc('hour', createdat) +
     (((date_part('minute', createdat)::integer / 10::integer) * 10::integer)|| ' minutes')::interval AS hr
    FROM datatable  
    group by deviceserial,hr,device
) t
group by deviceserial,device;

稍后我将对 device_usage_test1 进行 upsert 查询。所以我的设备序列号必须是唯一的。 但是当我尝试使用deviceserial(唯一)插入时。它给了我错误: ERROR:duplicate key value violates unique constraint "device_usage_deviceserial_key""

DETAIL: Key (deviceserial)=(636363636890) already exists.

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    您有数据问题。您的选择将返回至少 2 个具有相同设备序列 (1004573GT7) 的设备。尝试运行以下命令:

    select * 
      from (select deviceserial
                  ,device       
                  ,extract(epoch from (max(createdat)::timestamp - min(createdat)::timestamp)) as deviceusage
                  ,date_trunc('hour', createdat) +
                   (((date_part('minute', createdat)::integer / 10::integer) * 10::integer)|| ' minutes')::interval AS hr
             from datatable where createdat > now() - interval '1 day' 
            group by deviceserial,hr,device
           ) s
    having count(deviceserial)>1
    order by deviceserial;
    

    注意:没有给出表定义或示例数据,以上未测试。


    第二:
    不能拥有一个唯一的约束 deviceserail,同时为一个 deviceserail 拥有多个设备。根据定义,每个设备序列有多个设备在设备序列上不是唯一的。您可以改为在 (deviceserail,device) 上定义您的唯一键。

    drop table device_usage_test1; 
    create table device_usage_test1(id serial
                                   ,deviceserial varchar(50) 
                                   ,device varchar(50)
                                   ,deviceusage double precision
                                   ,constraint device_usage_test1_pk 
                                               primary key (id)
                                   ,constraint device_usage_test1_bk
                                               unique (deviceserial,device)
                                   );   
    

    但是,这允许您的初始不良数据同时具有“android”和“Android”共存。您可能希望限制设备上的大小写。例如:

    alter table device_usage_test1
            add constraint device_initcap_check 
                check (device = initcap(device));
    

    【讨论】:

    • 谢谢,@Belayer 您的查询给了我错误。我添加了示例数据。
    • 说是报错是没用的。什么错误!但在这种情况下,这是不必要的。样本数据的前 2 行足以检测初始错误。您按设备序列号、设备分组,但对设备序列号有唯一约束。由于“android”不等于“Android”,因此您有 2 个设备序列号为 636363636890 的组。因此违反了唯一约束。看起来您有 2 个选项:#1 并且首选 清理您的数据; #2 按设备序列分组; #3 按设备序列分组,initcap(device) - 但是选择哪个设备是不可预测的。
    • 谢谢,@Belayer。不知何故我没有注意到它。它现在正在使用示例数据。但在实际数据中没有大写和小写字母的问题。如果我从查询中删除设备并groupby 与 deviceSerial,它给出了成功的结果。但是如果我在查询中添加设备,它会给我错误。但我需要来自相应 deviceSerial 的设备列值。我对 Postgres 很陌生。任何想法,我如何选择设备而不放它在 groupby 中。
    • 查看修改后的答案。它会更改唯一键。
    • 谢谢@Belayer。它工作得很好。这是一个很大的帮助。如果我想用 upsert 查询 Postgres 哪个约束来更新表,我应该定位吗?冲突(设备序列号,设备)?这个表(device_usage_test1)每天都会更新不同的时间(createdAt)。
    猜你喜欢
    • 2012-03-03
    • 2020-05-28
    • 2018-08-16
    • 2020-02-15
    • 2016-07-27
    • 2012-06-20
    • 2016-06-06
    • 2011-10-17
    相关资源
    最近更新 更多