【问题标题】:PostgreSQL: Unique violation: 7 ERROR: duplicate key value violates unique constraint "users_pkey"PostgreSQL:唯一违反:7 错误:重复键值违反唯一约束“users_pkey”
【发布时间】:2016-10-24 13:19:57
【问题描述】:

我在我的 Laravel 应用程序中使用 psql。 我正在尝试创建我的用户,但我不断收到此错误

唯一违反:7 错误:重复键值违反唯一约束“users_pkey”


这是我为存储用户所做的操作

$user = User::where('account_id','=',$id)->first();
$user->email = $account->email_address;
$user->fb_email = '';
$user->tw_email = '';
$user->fb_access_token = '';
$user->fb_profile_id = '';
$user->fb_page_id = '';
$user->fb_username = '';
$user->save();

这是我创建用户表的方式

CREATE TABLE "users" (
    "id" serial NOT NULL ,
    "account_id" varchar(255) NOT NULL ,
    "email" varchar(255) NOT NULL ,
    "fb_email" varchar(255) NOT NULL ,
    "tw_email" varchar(255) NOT NULL ,
    "created_at" timestamp(0) without time zone,
    "updated_at" timestamp(0) without time zone,
    "fb_access_token" varchar(255) NOT NULL ,
    "fb_profile_id" varchar(255) NOT NULL ,
    "fb_page_id" varchar(255) NOT NULL ,
    "fb_username" varchar(255) NOT NULL ,
    PRIMARY KEY ("id")

);

我有没有做过我not 认为应该做的事情?

当我使用MySQL 挂钩我的应用程序时,我现在拥有的东西过去常常可以工作。

任何提示/建议对我来说意义重大。


截图

【问题讨论】:

  • 您的插入中没有 users_pkey,并且很可能没有使其成为数据库中的自动递增值,因此它获得了一个默认值,该默认值恰好已经存在于表,导致您的错误。
  • 肯定又是psql和mysql的区别了。
  • 如何将我的id 设为/使用我的 pkey ?有可能吗?

标签: php mysql postgresql laravel laravel-5


【解决方案1】:

Postgres 处理自动递增的方式与 MySQL 略有不同。在 Postgres 中,当您创建 serial 字段时,您还创建了一个跟踪要使用的 id 的序列字段。此序列字段将以 1 开始。

向表中插入新记录时,如果不指定id字段,则使用序列的值,然后递增序列。但是,如果您确实指定了 id 字段,则不会使用该序列,也不会更新它。

我假设当您迁移到 Postgres 时,您播种或导入了一些现有用户以及他们现有的 ID。当您使用他们的 id 创建这些用户记录时,该序列未被使用,因此从未更新。

因此,例如,如果您导入了 10 个用户,您的用户的 id 为 1-10,但您的序列仍为 1。当您尝试创建新用户而不指定 id 时,它会从序列 (1),你会得到一个唯一的违规,因为你已经有一个 id 为 1 的用户。

要解决此问题,您需要将 users_id_seq 序列值设置为现有用户的 MAX(id)。您可以阅读this question/answer 了解有关重置序列的更多信息,但您也可以尝试类似(未经测试):

SELECT setval(pg_get_serial_sequence('users', 'id'), coalesce(max(id)+1, 1), false) FROM users;

仅供参考,这在 MySQL 中不是问题,因为当手动将值插入自动递增字段时,MySQL 会自动将自动递增序列更新为最大列值。

【讨论】:

  • 你是 100% 正确的,在我手动提供了 id 之后,现在它可以工作了 perfectly 很好。
  • 很好的解释,不幸的是代码几乎对我有用-它将指针设置为最后一个插入的元素,但不是最后一个元素之后的下一个,所以它仍然无法工作,因为 PostgreSQL 试图添加一个新行使用最后使用的 id - 所以应该有 max(id)+1,但在测试这个建议之前,我使用了另一个对我有用的解决方案:SELECT setval('users_id_seq', (SELECT MAX(id) from "users"));
  • 这是我在 Stack Overflow 上得到的最佳答案。 100% 正确。非常详细
  • 我在+1 中添加了最大ID。当setval()的第三个参数为false时,下一次调用序列将返回setval()设置的值。如果您将第三个参数更改为true,或者将其删除,则对序列的下一次调用将返回setval() 设置的值之后的值。由于我们确保在没有行时默认为 1,因此我们希望对序列的下一次调用返回我们传递给 setval() 的内容,因此我们需要传递 max(id)+1 和第三个参数为 @987654337 @.
  • 这是一个非常好的答案,而我正是这样做的。从 mySQL 迁移到 Postgres。我在歌颂后者,但这个功能/错误不仅仅是令人讨厌。如果我有并发连接都增加 memberId 字段,这意味着我必须锁定数据库,获取下一个 val 并使用那个。我觉得这违背了自动递增/序列号的全部目的。实际上很糟糕。
【解决方案2】:

以下代码提供了一种在 Laravel 中执行此操作的方法,这是 OP 正在使用的。

// Get all the tables from your database
$tables = \DB::select('SELECT table_name FROM information_schema.tables WHERE table_schema = \'public\' ORDER BY table_name;'); 

// Set the tables in the database you would like to ignore
$ignores = array('admin_setting', 'model_has_permissions', 'model_has_roles', 'password_resets', 'role_has_permissions', 'sessions'); 

//loop through the tables
foreach ($tables as $table) { 

   // if the table is not to be ignored then:
   if (!in_array($table->table_name, $ignores)) { 

       //Get the max id from that table and add 1 to it
       $seq = \DB::table($table->table_name)->max('id') + 1; 

       // alter the sequence to now RESTART WITH the new sequence index from above        
       \DB::select('ALTER SEQUENCE ' . $table->table_name . '_id_seq RESTART WITH ' . $seq); 

    }

}

注意 - 使用 ALTER SEQUENCE “阻止并发事务”。如果不需要,请考虑使用上面提供的替代解决方案中的 SQL 语句。

【讨论】:

  • 只提供纯代码并不是一个好主意,因为很难理解为什么这段代码应该是问题的解决方案。请详细说明您的回答将如何解决问题。
  • @codedge 我编辑了答案并提供了每行 cmets 的上下文。对于 OP 正在使用的工具,即 Laravel (PHP),答案似乎是好的。我希望这对其他人有帮助。
【解决方案3】:

您还可以使用数据库管理软件编辑 PostgreSQL 中的每个表序列。例如我使用 pgAdmin4。只需检查该表的最新主键是什么,然后转到您的数据库 -> 架构 -> 1.3 序列 -> -> 属性 -> 定义和编辑字段当前值。

【讨论】:

    【解决方案4】:

    当您导出表并将其导入不同的数据库时,通常会发生此错误。

    以上方法都可以,可惜在我的系统上不行,我使用的系统是laravel和postgres。

    我通过清空桌子解决了我的问题

    TRUNCATE TABLE table_name;
    

    【讨论】:

      猜你喜欢
      • 2016-07-27
      • 2011-10-17
      • 2011-05-25
      • 2021-03-29
      • 2016-09-28
      • 2020-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多