PostgreSQL:唯一违规:7 错误:重复键值违反唯一约束“users_pkey”在这里,我做了什么来存储我的用户以下是我创建用户表的方式截图

2022-08-30 13:00:25

我在我的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

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


截图

enter image description here


答案 1

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

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

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

因此,例如,如果您导入了 10 个用户,则 id 为 1-10 的用户,但序列仍为 1。当您尝试在不指定 id 的情况下创建新用户时,它会从序列 (1) 中提取值,并且您会收到唯一的冲突,因为您已经有一个 id 为 1 的用户。

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

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

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


答案 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 语句。


推荐