【问题标题】:CakePHP: Unique violation: 7 ERROR: duplicate key value violates unique constraintCakePHP:唯一违反:7 错误:重复键值违反唯一约束
【发布时间】:2016-07-27 11:01:23
【问题描述】:

我在尝试删除一堆记录然后插入新记录后遇到以下错误:

Error: SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "routes_pkey" DETAIL: Key (id)=(1328) already exists.

SQL Query:
INSERT INTO routes (agency_id, route_identifier, short_name, long_name, description, route_color, text_color) VALUES (:c0, :c1, :c2, :c3, :c4, :c5, :c6) RETURNING *

这是代码的简化版本:

    $routes = TableRegistry::get('Routes');
    $routes->deleteAll(['agency_id' => $agency->id]);

    # Data to be updated
    $patchData = [
        'stops' => $stopData,
        'static_data_modified' => Time::now()
    ];

    $patchOptions = [
        'associated' => ['Stops.Routes']
    ];

    # If: The stops have already been added to the DB
    # Then: Remove them from the patch data
    if (isset($stopData['_ids'])) {
        unset($patchData['stops']);

        # Change settings for this implementation type
        $patchOptions = [];
        $stopCount = count($stopData['_ids']);
    }

    $agency = $this->Agencies->patchEntity($agency, $patchData, $patchOptions);

    $this->Agencies->save($agency);

似乎出于某种原因,Postgres 认为我正在插入具有重复主键的记录。但我无法从我的代码中看出这是如何实现的。

这是我在 SQL 日志末尾看到的内容:

DELETE FROM 
  routes 
WHERE 
  agency_id = 51

BEGIN

SELECT 
  1 AS "existing" 
FROM 
  agencies Agencies 
WHERE 
  Agencies.id = 51 
LIMIT 
  1

INSERT INTO routes (
  agency_id, route_identifier, short_name, 
  long_name, description, route_color, 
  text_color
) 
VALUES 
  (
    51, '100001', '1', '', 'Kinnear - Downtown Seattle', 
    '', ''
  ) RETURNING *

ROLLBACK

知道为什么我会看到此错误吗?

我正在使用带有 Postgresql 9.4 的 CakePHP v3.1

我尝试添加它,但它没有改变任何东西:

$connection = ConnectionManager::get('default');
$results = $connection->execute('SET CONSTRAINT = routes_pkey DEFERRED');

以下是我读过但没有找到解决方案的类似问题:

更新 根据 muistooshort 的评论,我从路由表中删除了所有记录并重新运行代码,它工作正常。之后我第二次运行它时它也运行良好。所以我认为这支持 mu 的理论,即数据库中的现有记录(不是我的代码)有问题。我认为现在更好的问题是数据库中究竟是什么情况导致了这种情况,我该如何解决?

【问题讨论】:

  • 您是否手动分配ids 或执行其他操作导致id 值与提供id 值的序列不同步?
  • @muistooshort 当然不是故意的,但也许是无意中发生的?你能详细说明我应该寻找什么吗?如果记录的 ID 号较低但数据库中已有较高的 ID,Postgres 会被愚弄吗?类似的东西?
  • @muistooshort 我想我的问题是我应该在数据库中寻找什么症状来确定你的理论是否有问题?
  • @muistooshort 在问题底部查看我的更新。
  • serial PostgreSQL 中的列从序列中获取默认值。如果您插入带有显式 id 的新行,则将使用 id 但序列不会知道它,因此当 serial 列询问时,它将为您提供该值(当它到达时)默认值(例如:sqlfiddle.com/#!15/17534/1)。您可以使用setval 重置序列以匹配表中的ids。

标签: php database postgresql cakephp cakephp-3.0


【解决方案1】:

PostgreSQL 中的serial type 非常简单:它本质上是一个integer 列,其默认值来自sequence。但是序列不知道你对表做了什么,所以如果你为 serial 指定一个值而不使用或更新序列,事情就会变得混乱。

例如:

create table t (
  id serial not null primary key
);
insert into t (id) values (1);
insert into t (id) values (DEFAULT);

将产生唯一性违规,因为1 已明确用于id,但序列无法知道它已被使用。

演示http://sqlfiddle.com/#!15/17534/1

大概在某个时候某处某处添加了带有id = 1328 的行,而没有来自序列的id。或者,您的 PK 默认使用的序列可能已使用 setval 进行了调整,以开始返回表中已经存在的值。

无论如何,最简单的做法是使用setval 调整顺序以匹配表格的当前内容:

select setval('routes_id_seq', (select max(id) from routes));

该序列应称为routes_id_seq,但如果不是,您可以在psql 中使用\d routes 来找出它的名称。

因此,如果我们将前面的示例更新为:

create table t (
  id serial not null primary key
);
insert into t (id) values (1);
select setval('t_id_seq', (select max(id) from t));
insert into t (id) values (DEFAULT);

然后我们将在我们的表中得到12 而不是1 和一个错误。

演示http://sqlfiddle.com/#!15/17534/7

【讨论】:

  • 宾果游戏!有一个使用COPY 的脚本,我们现在知道它不会自动推进序列。更多细节在这里:stackoverflow.com/questions/9091781/…
  • 对,COPY 会这样做,因为这只是向包含id 值的INSERT 提供数据的一种奇特方式。很高兴看到你也通过了 10k 障碍 :)
猜你喜欢
  • 2016-10-24
  • 2013-03-15
  • 2020-02-15
  • 2011-10-17
  • 2012-03-03
  • 2018-08-26
  • 2021-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多