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 中对 json 类型使用唯一约束
PostgreSQL BigSerial错误:重复的键值违反了唯一约束“ investigations_pkey” [duplicate]