在Postgres中为Insert语句生成UUID?

ano*_*932 318 postgresql uuid postgresql-8.4

我的问题很简单.我知道UUID的概念,我想生成一个从我的DB中的'store'引用每个'item'.看似合理吧?

问题是以下行返回错误:

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.
Run Code Online (Sandbox Code Playgroud)

我已经阅读了以下网页:http://www.postgresql.org/docs/current/static/uuid-ossp.html

在此输入图像描述

我在Ubuntu 10.04 x64上运行Postgres 8.4.

Cra*_*ger 391

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

对于现代PostgreSQL版本(9.1和更新版本)来说,这很简单:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
Run Code Online (Sandbox Code Playgroud)

但对于9.0及更低版本,您必须运行SQL脚本来加载扩展.请参阅8.4中的contrib模块文档.

对于Pg 9.1和更新版本,请阅读当前的contrib文档CREATE EXTENSION.这些功能在9.0或更早版本中不存在,例如8.4.

如果您使用的是PostgreSQL的打包版本,则可能需要安装包含contrib模块和扩展的单独软件包.在您的包管理器数据库中搜索"postgres"和"contrib".

  • @advocate你正在使用一个发行版打包的PostgreSQL,所以你应该只能`apt-get install postgresql-contrib`或类似的东西.尝试使用`apt-cache search postgresql | grep contrib`来查找所需的包名称. (5认同)
  • 请注意,如果您不安装`postgresql-contrib`包,则会收到错误:_ERROR:无法打开扩展控制文件"/usr/share/postgresql/9.3/extension/uuid-ossp.control":没有相应的文件和目录_ (5认同)
  • sudo apt-get install postgresql-contrib已成功运行.然后我不得不运行psql -d dbname -f SHAREDIR/contrib/module.sql现在它的工作原理!select uuid_generate_v1(); 现在返回1.非常感谢! (2认同)
  • 如果您已在扩展中导入了具有 uuid-ossp 的数据库,则 uuid_generate_v4() 可能不起作用。如果是这种情况,只需删除扩展名,然后重新创建它就可以了。 (2认同)
  • 使用“IF NOT EXISTS”是一种很好的做法,尤其是在任何 sql 脚本中 - 它可以防止在重新运行脚本或将其传输到已加载该脚本的另一个系统时发出错误。(我刚刚将其添加到答案中。) (2认同)

Zuz*_*zEL 254

没有扩展(作弊)

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

output>> c2d29867-3d0b-d497-9191-18a9d8ee7830
Run Code Online (Sandbox Code Playgroud)

(至少在8.4中起作用)

  • 感谢@Erwin Brandstetter的clock_timestamp()解释.

如果您需要有效的v4 UUID

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

在此输入图像描述 *感谢@Denis Stafichuk @Karsten@autronix


此外,在现代Postgres中,您可以简单地演员:

SELECT md5(random()::text || clock_timestamp()::text)::uuid

  • @JosephLennox:[`clock_timestamp()`](http://www.postgresql.org/docs/current/interactive/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT)在这两种情况下都是更好的选择.与`now()`或`CURRENT_TIMESTAMP`不同,它是volatile并返回实际的当前时间.`SELECT uuid_in(md5(random():: text || clock_timestamp():: text):: cstring);`此外,在现代Postgres中,你可以简单地演员:`SELECT md5(random():: text || clock_timestamp():: text):: uuid` - 不需要更多魔法.使用案例:http://stackoverflow.com/a/8335376/939860 (24认同)
  • 不.如果这确实起作用,那绝对幸运.UUID有一种格式,它不仅仅是随机的十六进制字符组合在一起.第三组的第一个数字是intance的uuid版本(这些天通常是4).如果您的应用程序检查该数字以查看其处理的uuid版本,并相应地执行某些操作,则它将在您的代码中失败. (17认同)
  • @TuncayGöncüoğlu:生成有效的v4 UUID相当简单(字符串覆盖方法虽然浪费了2位随机性):`select overlay(overlay(md5(random():: text ||':'|| clock_timestamp() :: text)放置来自13的'4')从17)放置'8':: uuid;` (6认同)
  • 跟进你的PS:SELECT`uuid_in(md5(random():: text || now():: text):: cstring);` (5认同)
  • @MattDiPasquale可能没有比使用`uuid-ossp`更好的"更好",但我是在一个PostgreSQL实例上工作,我没有足够的权限来安装扩展. (4认同)
  • 我认为在答案中提到的任何方法中使用“clock_timestamp”都没有意义,因为数据无论如何都会输入“md5”,因此会丢失。因此我们可以简单地使用`md5(random()::text || random()::text)::uuid`:使用`random`(返回`双精度`,即64位)两次给我们128位的随机信息,通过“md5”转换为不同(但仍然是随机的)128位数字的十六进制表示。 (3认同)
  • @Karsten,我通过取回那些2位randmoness来改进你的样本:`overlay(覆盖(md5(random():: text ||':'|| clock_timestamp():: text)放置'4'来自13)放置楼层(random()*(11-8 + 1)+ 8)::来自17的文本:: uuid;`这应该补偿版本和变体,同时仍然保留变量的2 LSB`10xx`部分. (2认同)
  • @autronix,实际上您已将其破坏。您需要将`floor(random()*(11-8 + 1)+ 8)`转换为十六进制以使其正确。这是更正后的版本:`select overlay(overlay(md5(random():: text ||':'|| clock_timestamp():: text))从13放置'4')to_hex(floor(random()*( 11-8 + 1)+ 8):: int)::来自17):: uuid的文本; (2认同)
  • @RobinJonsson 没什么可疑的。UUID 版本 4 不是基于时间的。https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(日期时间和MAC地址) (2认同)

Bas*_*que 66

克雷格林格答案是正确的.这是Postgres 9.1及更高版本的更多信息......

扩展可用吗?

如果已经为Postgres安装(Postgres术语中的群集)构建了扩展,则只能安装扩展.例如,我发现UUID-OSSP包括作为麻烦安装的Mac OS X的一部分延伸设置由EnterpriseDB.com.可能有几十个扩展中的任何一个.

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

SELECT * FROM pg_available_extensions;
Run Code Online (Sandbox Code Playgroud)

安装扩展

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

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
Run Code Online (Sandbox Code Playgroud)

注意:我发现要求扩展名称周围的QUOTATION MARK字符,尽管文档相反.

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

验证安装

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

SELECT * FROM pg_extension;
Run Code Online (Sandbox Code Playgroud)

UUID为默认值

有关详细信息,请参阅问题:Postgres中UUID列的默认值

旧路

以上信息使用Postgres 9.1中添加的新扩展功能.在以前的版本中,我们必须在.sql文件中查找并运行脚本.添加扩展功能是为了使安装更容易,为扩展创建者交换更多的工作,以减少扩展的用户/消费者的工作.有关更多讨论,请参阅我的博文.

UUID的类型

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

例如,原始版本1将主计算机的MAC地址与当前日期时间和任意数字组合在一起,碰撞的几率几乎为零.

有关更多讨论,请参阅对相关问题的回答.

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

bri*_*out 57

pgcrypto 延期

截至Postgres 9.4,该pgcrypto模块包含该gen_random_uuid()功能.此函数生成一个基于随机数的版本4类型的UUID.

获取contrib模块(如果尚未提供).

sudo apt-get install postgresql-contrib-9.4
Run Code Online (Sandbox Code Playgroud)

使用pgcrypto模块.

CREATE EXTENSION "pgcrypto";
Run Code Online (Sandbox Code Playgroud)

gen_random_uuid()功能现在应该可用;

用法示例.

INSERT INTO items VALUES( gen_random_uuid(), 54.321, 31, 'desc 1', 31.94 ) ;
Run Code Online (Sandbox Code Playgroud)


Postgres doc上uuid-ossp引用模块.

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

  • 是的,但另请参阅https://blog.starkandwayne.com/2015/05/23/uuid-primary-keys-in-postgresql/,他们会警告碎片并建议使用uuid-ossp. (3认同)
  • 实际上,请参阅https://www.postgresql.org/message-id/20151222124018.bee10b60b3d9b58d7b3a1839%40potentialtech.com,其中Postgres中的uuid碎片问题被揭穿 (3认同)
  • @MichaelGoldshteyn:不,Postgres **没有** 有聚集索引(从 Postgres 12 开始) (2认同)

Luk*_*zda 38

的PostgreSQL 13支撑本身 gen_random_uuid()

PostgreSQL 包括一个生成 UUID 的函数:

gen_random_uuid () ? uuid
Run Code Online (Sandbox Code Playgroud)

此函数返回版本 4(随机)UUID。这是最常用的 UUID 类型,适用于大多数应用程序。

db<>小提琴演示

  • 我不明白为什么有这么多其他(无效)答案,就这么简单!应该是公认的答案 (13认同)
  • @pdem 因为 PostgreSQL 13 相当新。例如,我仍在开发服务器版本 10。不过,这似乎是版本 13 的最佳替代方案。 (11认同)
  • @borellini我明白,我实际上在12中有一个生产服务器,我必须创建这个补丁函数才能使其工作 `create function gen_random_uuid() RETURNS uuid as $$ SELECT md5(random()::text ||clock_timestamp() ::text)::uuid $$ LANGUAGE SQL;` (6认同)

Bek*_*eki 9

从 2021 年开始更新,无需花哨的技巧来自动生成uuidoninsert语句。

只做一件事:

  1. 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)
);
Run Code Online (Sandbox Code Playgroud)

现在您无需执行任何操作即可将 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'
)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 正如 Lukasz Szozda 在 /sf/answers/4337960861/ 中指出的那样,从 PostgreSQL *13* 开始,`gen_random_uuid()` 在 _core_ PostgreSQL 中可用(因此不需要安装任何扩展)。 (2认同)

小智 8

Postgres v13+

INSERT INTO your_table
VALUES (gen_random_uuid(), 'value column 2', 'value column 3')
Run Code Online (Sandbox Code Playgroud)


小智 5

ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);
Run Code Online (Sandbox Code Playgroud)

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


小智 5

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

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

  1. 添加扩展

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

  1. 验证扩展

从 pg_extension 中选择*;

  1. 运行查询

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

验证表数据