ChatGPT解决这个技术问题 Extra ChatGPT

在 Postgres 中为插入语句生成 UUID?

我的问题很简单。我知道 UUID 的概念,我想生成一个来引用我数据库中“商店”中的每个“项目”。看起来很合理吧?

问题是以下行返回错误:

honeydb=# insert into items values(
uuid_generate_v4(), 54.321, 31, 'desc 1', 31.94);
ERROR:  function uuid_generate_v4() does not exist
LINE 2: uuid_generate_v4(), 54.321, 31, 'desc 1', 31.94);
        ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

我已阅读页面:http://www.postgresql.org/docs/current/static/uuid-ossp.html

https://i.stack.imgur.com/BDeZ3.png

我在 Ubuntu 10.04 x64 上运行 Postgres 8.4。

Postgres 原生支持 UUID 作为数据类型,甚至能够被索引并用作主键。但是要生成 UUID 值,例如为列建立默认值,您需要一个Postgres 扩展(一个插件)。 Postgres 的许多构建(发行版)都包含这样的扩展,但不激活该扩展。请参阅 correct answer by Craig Ringer 了解如何激活它。
如果你安装了 uuid-ossp &您仍然会收到此错误尝试使用您的架构名称为函数添加前缀,例如 select dbo.uuid_generate_v4()

C
Craig Ringer

uuid-ossp 是一个贡献模块,因此默认情况下它不会加载到服务器中。您必须将其加载到数据库中才能使用它。

对于现代 PostgreSQL 版本(9.1 和更高版本),这很容易:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

但对于 9.0 及以下版本,您必须改为运行 SQL 脚本来加载扩展。请参阅the documentation for contrib modules in 8.4

对于 Pg 9.1 和更新版本,请改为阅读 the current contrib docsCREATE EXTENSION。这些功能在 9.0 或更早版本中不存在,例如您的 8.4。

如果您使用的是 PostgreSQL 的打包版本,您可能需要安装一个包含 contrib 模块和扩展的单独包。在您的包管理器数据库中搜索“postgres”和“contrib”。


@advocate 您使用的是发行版打包的 PostgreSQL,因此您应该只能使用 apt-get install postgresql-contrib 或类似的。尝试 apt-cache search postgresql |grep contrib 找到您想要的包名称。
sudo apt-get install postgresql-contrib 已成功运行。然后我不得不运行 psql -d dbname -f SHAREDIR/contrib/module.sql 现在它可以工作了!!!选择 uuid_generate_v1();现在返回 1。非常感谢!
请注意,如果您不安装 postgresql-contrib 软件包,您将收到错误消息:ERROR: could not open extension control file "/usr/share/postgresql/9.3/extension/uuid-ossp.control" : 没有这样的文件或目录
当错误字符串在 Google 上被删除时,我发布了该评论。它还给出了一个特定的包名称,至少对于 Ubuntu。
如果您已在 Extensions 中导入了具有 uuid-ossp 的数据库,则 uuid_generate_v4() 可能无法正常工作。如果是这种情况,只需删除扩展名,然后重新创建它,它应该可以工作。
Z
ZuzEL

没有扩展名(作弊)

如果您需要有效的 v4 UUID

SELECT uuid_in(overlay(overlay(md5(random()::text || ':' || random()::text) placing '4' from 13) placing to_hex(floor(random()*(11-8+1) + 8)::int)::text from 17)::cstring);

https://i.stack.imgur.com/OA6Qk.png

感谢@Denis Stafichuk @Karsten 和 @autronix

或者您可以通过这样做简单地获得类似 UUID 的值(如果您不关心有效性):

SELECT uuid_in(md5(random()::text || random()::text)::cstring);

output>> c2d29867-3d0b-d497-9191-18a9d8ee7830

(至少在 8.4 中有效)


要跟进您的 PS:选择 uuid_in(md5(random()::text || now()::text)::cstring);
@MattDiPasquale 可能在任何意义上都没有比使用uuid-ossp“更好”,但例如我正在处理一个 PostgreSQL 实例,我没有足够的权限来安装扩展。
@JosephLennox:clock_timestamp() 在这两种情况下都是更好的选择。与 now()CURRENT_TIMESTAMP 不同,它是可变的并返回实际的当前时间。 SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring); 此外,在现代 Postgres 中,您可以简单地转换:SELECT md5(random()::text || clock_timestamp()::text)::uuid - 不需要更多魔法。用例:stackoverflow.com/a/8335376/939860
没有。如果这确实有效,那真是太幸运了。 UUID 有一个格式,它不仅仅是随机的十六进制字符。第三组的第一个数字是实例的 uuid 版本(现在通常是 4 个)。如果您的应用程序检查该数字以查看其处理的 uuid 版本,并相应地执行某些操作,它将在您的代码中失败。
@Tuncay Göncüoğlu:生成有效的 v4 UUID 相当简单(字符串覆盖方法虽然浪费了 2 位随机性):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
L
Lukasz Szozda

PostgreSQL 13 原生支持 gen_random_uuid ()

PostgreSQL 包含一个生成 UUID 的函数: gen_random_uuid () → uuid 此函数返回版本 4(随机)UUID。这是最常用的 UUID 类型,适用于大多数应用程序。

db<>fiddle demo


我不明白为什么还有这么多其他(非工作)答案,就这么简单!应该是公认的答案
@pdem,因为 PostgreSQL 13 相当新。例如,我仍在使用服务器版本 10。不过,这似乎是版本 13 的最佳替代方案。
@borellini 我明白了,我实际上在 12 年有一个生产服务器,我必须创建这个补丁函数才能让它工作create function gen_random_uuid() RETURNS uuid as $$ SELECT md5(random()::text || clock_timestamp()::text)::uuid $$ LANGUAGE SQL;
我喜欢这个 polyfill,易于升级。
B
Basil Bourque

answer by Craig Ringer 是正确的。这是 Postgres 9.1 及更高版本的更多信息……

扩展可用吗?

如果扩展已经为您的 Postgres 安装构建(您的 cluster 在 Postgres 术语中),您只能安装扩展。例如,我发现 EnterpriseDB.com 将 uuid-ossp 扩展作为 Mac OS X 安装程序的一部分providedfew dozen extensions 中的任何一个都可能可用。

要查看 uuid-ossp 扩展是否在您的 Postgres 集群中可用,请运行此 SQL 以查询 pg_available_extensions 系统目录:

SELECT * FROM pg_available_extensions;

安装扩展

要安装与 UUID 相关的扩展,请使用如下 SQL 中所示的 CREATE EXTENSION 命令:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

注意:我发现扩展名周围的引号字符是必需的,尽管文档相反。

SQL 标准委员会或 Postgres 团队为该命令选择了一个奇怪的名称。在我看来,他们应该选择“安装扩展”或“使用扩展”之类的东西。

验证安装

您可以通过运行此 SQL 查询 pg_extension 系统目录来验证扩展是否已成功安装在所需的数据库中:

SELECT * FROM pg_extension;

UUID 作为默认值

有关详细信息,请参阅问题:Default value for UUID column in Postgres

老路

以上信息使用 Postgres 9.1 的新 Extensions 功能 added。在以前的版本中,我们必须在 .sql 文件中查找并运行脚本。添加了扩展功能以简化安装,为 creator of an extension 换取更多的工作,以减少扩展的用户/消费者的工作。有关更多讨论,请参阅我的 blog post

UUID 的类型

顺便说一句,问题中的代码调用了函数 uuid_generate_v4()。这会生成一种称为 Version 4 的类型,其中几乎所有 128 位都是随机生成的。虽然这适用于较小的行集的有限使用,但如果您想几乎消除任何冲突的可能性,请使用 UUID 的另一个“版本”。

例如,原始的Version 1将主机的MAC address与当前日期时间和任意数字组合在一起,碰撞的可能性几乎为零。

如需更多讨论,请参阅相关问题的my Answer


如果您不确定并且不想检查(例如在脚本中),您也可以使用 CREATE EXTENSION IF NOT EXISTS ...
版本 4 UUID 几乎适用于任何大小的数据集,而不仅仅是“在较小的行集上有限使用”。您必须在大约 85 年内每秒生成 10 亿个 UUID(或大约 4500 万 TB 的数据,比当今最大的数据库大数千倍)才能有 50% 的碰撞机会。除非您是 NSA,否则版本 4 几乎适用于任何目的。另一方面,版本 1 的问题是 MAC 地址是按顺序分配的(并且经常被欺骗或不可用),这也是引入更高版本的部分原因。
@BasilBourque v1 的问题不是正确实施时发生冲突的可能性,而是错误实施的可能性。正如 Wikipedia 所说:“版本 1 和 2 UUID 的唯一性……还取决于网卡制造商正确地为其卡分配唯一的 MAC 地址,这与其他制造过程一样容易出错。”此外,在某些容器化或虚拟化环境中,来自底层硬件的真实 MAC 地址不可用。如果许多容器具有相同的 MAC 但它们自己的 clockseq 计数器,它们的 v1 UUID 可能会发生冲突。
不过,v1 中的@BasilBourque 弱点并不是我评论的重点。您的原始答案暗示 v4 不适合大型数据集,因为冲突概率高于 v1。这是误导性的,并且可能是错误的,尽管很难计算 v1 的冲突概率,因为它是如此依赖于实现。
@BasilBourque 例如,node-uuid 项目计算它们的clockseq 计数器与4.6e18 中的1 相同(以便两个进程将生成相同的v1 UUID 序列)的概率。这是很小的,是的,但比 v4 中立即碰撞的可能性要大得多,在 5.3e36 中是 1。显然,您生成 v4 UUID 的时间越长,发生冲突的可能性就越大,而 v1 并非如此,但您必须生成 15.2 亿个 v4 UUID,然后冲突概率超过节点的 v1 实现。大多数人没有每张表有 15.2 亿条记录。
B
Basil Bourque

pgcrypto 扩展

从 Postgres 9.4 开始,pgcrypto 模块包括 gen_random_uuid() 函数。此函数生成基于随机数的 Version 4 type of UUID 之一。

获取 contrib 模块(如果尚不可用)。

sudo apt-get install postgresql-contrib-9.4

使用 pgcrypto 模块。

CREATE EXTENSION "pgcrypto";

gen_random_uuid() 函数现在应该可用;

示例用法。

INSERT INTO items VALUES( gen_random_uuid(), 54.321, 31, 'desc 1', 31.94 ) ;


引自 Postgres doc on uuid-ossp 模块。

注意:如果您只需要随机生成的(版本 4)UUID,请考虑使用 pgcrypto 模块中的 gen_random_uuid() 函数。


是的,但另请参阅blog.starkandwayne.com/2015/05/23/…,他们警告碎片并建议使用 uuid-ossp。
实际上,请参阅 postgresql.org/message-id/…,其中 Postgres 中的 uuid 碎片问题已被揭穿
但是 postgres 在最新版本中确实有聚集索引,使得上述评论中链接的帖子不确定且不正确,我们马上回到第 1 格。
@MichaelGoldshteyn:不,Postgres 没有聚集索引(从 Postgres 12 开始)
第一条评论中的文章已移动 here。但是,TLDR,关于揭穿“碎片化”问题的第二个链接找到了开始神话的文章,它基于具有聚集索引的数据库,正如@a_horse_with_no_name 所说,postgres 没有。它具有对数据进行一次性重新排序的功能,因此键被聚集在一起,但它与 SQL Server 不同。 SQL Server 可以存储按键排序的行,并在添加新记录时随机排列以保持键的顺序。
l
labulaka

从 2021 年开始更新,无需花哨的技巧即可在 insert 语句上自动生成 uuid

只做一件事:

将 DEFAULT gen_random_uuid () 的默认值设置为您的 uuid 列。就这些。

说,你有一张这样的桌子:

CREATE TABLE table_name (
    unique_id UUID DEFAULT gen_random_uuid (),
    first_name VARCHAR NOT NULL,
    last_name VARCHAR NOT NULL,
    email VARCHAR NOT NULL,
    phone VARCHAR,
    PRIMARY KEY (unique_id)
);

现在您无需执行任何操作即可将 uuid 值自动插入 unique_id 列。因为您已经为它定义了一个默认值。您可以只专注于插入其他列,postgresql 会处理您的 unique_id。这是一个示例插入语句:

INSERT INTO table_name (first_name, last_name, email, phone) 
VALUES (
    'Beki',
    'Otaev',
    'beki@bekhruz.com',
    '123-456-123'
)

请注意,没有插入到 unique_id 中,因为它已经被处理了。

关于 uuid-ossp 等其他扩展,如果您对 postgres 的标准 gen_random_uuid () 功能不满意,可以启用它们。大多数时候,没有它们你应该没问题


正如 Lukasz Szozda 在 stackoverflow.com/a/61970869/13950739 中指出的那样,从 PostgreSQL 13 开始,gen_random_uuid()core PostgreSQL 中可用(因此不需要安装任何扩展)。
在本文的底部:starkandwayne.com/blog/uuid-primary-keys-in-postgresql 讨论了 gen_random_uuid() 的可能骗局。对声明的有效性有何评论?
如果您的意思是 negative side effect with respect to keyspace fragmentation,那么:不,这不是问题:postgresql.org/message-id/… – 如对 brillout 答案的评论中所述
P
Paolo Fernandes
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);

阅读@ZuzEL 的答案后,我使用上面的代码作为列 id 的默认值,它工作正常。


S
Satish Mali

uuid-ossp 模块提供生成通用唯一标识符 (UUID) 的功能

uuid_generate_v1() 此函数生成版本 1 UUID。

添加扩展

如果不存在“uuid-ossp”,则创建扩展;

验证扩展

选择 * 从 pg_extension;

运行查询

INSERT INTO table_name(id, column1, column2 , column3, ...) 值 (uuid_generate_v1(), value1, value2, value3...);

验证表数据


k
keemsisi

试试这个:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";  
SELECT uuid_generate_v1();

激活后,您可以调用 uuid_generate_v1() 生成随机 UUID


s
skyho
SELECT uuid_generate_v5(uuid_ns_url (), 'test');