postgresql字段值唯一约束

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了postgresql字段值唯一约束相关的知识,希望对你有一定的参考价值。

参考技术A postgresql 允许设置多个字段为值唯一的约束。
使用 pgAdmin 4 设置起来很方便。而且在 postgresql 6.5.1 是默认安装就具备的工具。

首先找到你要设置约束的表

鼠标右键选择属性

选择强制>约束

点击 + 号 新增一个约束

输入内容,选择要设置的字段

最后点击 保存按钮

字段值唯一约束就建立成功了。
之后你就会发现,除非是空值,否则你设置的字段内是不会有重复值的。

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

【中文标题】PostgreSQL:唯一违反:7 错误:重复键值违反唯一约束“users_pkey”【英文标题】:PostgreSQL: Unique violation: 7 ERROR: duplicate key value violates unique constraint "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 ?有可能吗? postgresql.org/docs/8.1/static/datatype.html#DATATYPE-SERIAL 【参考方案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;

【讨论】:

以上是关于postgresql字段值唯一约束的主要内容,如果未能解决你的问题,请参考以下文章

如何更新 postgreSQL 唯一键约束

如何在 postgresql 中对 json 类型使用唯一约束

SQLServer主键和唯一约束的区别

postgresql 重复键违反唯一约束

PostgreSQL BigSerial错误:重复的键值违反了唯一约束“ investigations_pkey” [duplicate]

mongodb 索引唯一性约束