如何创建包含多列MD5的GENERATED列?

2024-05-22

我尝试在 PostgreSQL 14.3 中添加下表:

CREATE TABLE client_cache (
    id            BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
    request       VARCHAR COMPRESSION lz4 NOT NULL CHECK (LENGTH (request) <= 10240),
    request_body  BYTEA COMPRESSION lz4 NOT NULL CHECK (LENGTH (request_body) <= 1048576),
    request_hash VARCHAR GENERATED ALWAYS AS (MD5(ROW(request::BYTEA, request_body)::VARCHAR)) STORED
);

但 Postgres 抱怨道:

[42P17] ERROR: generation expression is not immutable

我看到很多答案讨论如何创建GENERATED列包含MD5单列,但一旦添加ROW()计算MD5在多个列上,表达式不再是不可变的。

我可以创建一个GENERATED列使用ROW(MD5(A), MD5(B))但不是MD5(ROW(A, B)).

我可以做什么来创建一个MD5不同类型的多个列的值(如上所示)?

我知道我可以使用触发器创建视图或填充列,但我真的想坚持使用GENERATED如果可能的话列。


我建议使用一个不可变的辅助函数:

CREATE OR REPLACE FUNCTION f_request_md5(_request text, _request_body bytea)
  RETURNS uuid
  LANGUAGE sql IMMUTABLE PARALLEL SAFE AS 
'SELECT md5(textin(record_out((md5(_request_body), _request))))::uuid';

还有一个像这样的表:

CREATE TABLE client_cache (
  id           bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY
, request      text   COMPRESSION lz4 NOT NULL CHECK (length(request) <= 10240)
, request_body bytea  COMPRESSION lz4 NOT NULL CHECK (length(request_body) <= 1048576)
, request_hash uuid   GENERATED ALWAYS AS (f_request_md5(request, request_body)) STORED
);

数据库小提琴

注意更有效uuid代替varchar. See:

  • MD5 字段的最佳数据类型是什么? https://dba.stackexchange.com/a/115316/3684

背景

有两种重载变体md5()在 Postgres 14(或任何支持的版本)中:

test=> SELECT (proargtypes::regtype[])[0], prorettype::regtype, provolatile
test-> FROM   pg_proc
test-> WHERE  proname = 'md5';
 proargtypes | prorettype | provolatile 
-------------+------------+-------------
 bytea       | text       | i
 text        | text       | i
(2 rows)

一个需要bytea, one text, 两者都是IMMUTABLE并返回text。所以这个表达式是不可变的:

ROW(MD5(request), MD5(request_body))

但这并不像您通过艰难的方式发现的那样:

MD5(ROW(A, B)::varchar)

a 的文本表示record不是一成不变的。原因有很多。本案的一个明显原因是:bytea输出可以在(默认)hex格式或已过时escape格式。一个平原

SET bytea_output = 'escape'; 

...会破坏您生成的列。

获取一个不可变的文本表示bytea值,你会运行它encode(request_body, 'hex') https://www.postgresql.org/docs/current/functions-binarystring.html#FUNCTION-ENCODE。但不要去那里。md5(request_body)为我们的目的提供了更快的不可变文本“表示”。

我们仍然无法录制唱片。所以我创建了包装函数。请务必阅读此相关答案以获取更多说明:

  • 为什么我的 UNIQUE 约束没有触发? https://dba.stackexchange.com/a/299107/3684

就像该答案中讨论的那样,新的内置函数hash_record_extended()将会much更有效地达到目的。所以如果一个bigint已经足够好了,考虑一下:

CREATE TABLE client_cache2 (
  id           bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY
, request      text   COMPRESSION lz4 NOT NULL CHECK (length(request) <= 10240)
, request_body bytea  COMPRESSION lz4 NOT NULL CHECK (length(request_body) <= 1048576)
, request_hash bigint GENERATED ALWAYS AS (hash_record_extended((request, request_body), 0)) STORED
);

相同的数据库小提琴

在 Postgres 14 或更高版本中开箱即用。

Related:

  • 为什么在 PostgreSQL 中创建生成列时出现错误? https://stackoverflow.com/questions/60249404/why-am-i-getting-a-an-error-when-creating-a-generated-column-in-postgresql
  • PostgreSQL 中的计算/计算/虚拟/派生列 https://stackoverflow.com/questions/8250389/computed-calculated-virtual-derived-columns-in-postgresql/8250729#8250729
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何创建包含多列MD5的GENERATED列? 的相关文章

随机推荐

  • 用于解析差异的 PHP 类

    我正在编写一个 PHP 脚本 需要解释 Git 创建的 Diff 文件 如果我想解析 Diff 文件并基本上以完全不同的格式打印它 我应该如何进行 我遇到过Text DiffPEAR 库 但该库仅创建 Diff 本身 或者更确切地说 它只需
  • 这个花括号约定的名称是什么?

    我对看到有多少开发人员在类名或方法下方使用大括号编写方法和类感到有点困惑 他们遵循什么惯例 Sun 明确指出 http www oracle com technetwork java codeconventions 141270 html
  • 使用BFG时可以指定多个文件吗?

    我正在尝试删除通配符无法覆盖的多种类型的文件 我尝试使用多个 delete files 但它不接受它 还尝试将文件全部放在 delete files 之后 但它也不接受它 有没有一种方法可以将它们全部放在一个命令中 如果没有 那么我必须运行
  • 打印带有图像的 html(每个图像在单独的页面上)

    我有一个带有图像的 HTML img img img img 打印时 我希望每个图像都位于单独的页面上 根据打印尺寸 现在我把图像从中间切掉了 有什么办法可以解决吗 您可以尝试以下方法 p p
  • 使用 JavaScript 以编程方式编辑 Google 文档

    我想做的是运行一些 JavaScript 代码 将文本输入到 Google 文档中 到目前为止 我所做的是在我的个人网页上创建一个嵌入 Google 文档的 iframe 元素 目前我想做的是使用 Google 源代码中的函数来输入文本 当
  • 在Windows上安装smtplib的命令是什么

    我尝试使用以下命令在我的 Windows PC 上安装 smtplibpip and easy install但遇到以下错误 有人能告诉我如何在 Windows 上安装 smtplib 吗 C gt pip install smtplib
  • 以编程方式访问 Google App Engine 配额详细信息

    有谁知道是否可以通过 App Engine SDK 内的代码或某种形式的 WebAPI 访问您当前帐户配额的详细信息 我希望能够跟踪正在运行的应用程序中的数据存储使用情况和带宽使用情况 以便它可以根据应用程序剩余的配额级别来改变其行为 您可
  • Solr/Solrj 分页

    我正在创建的 Web 应用程序中使用 solr 和 solrj 来实现索引和搜索功能 我的请求处理程序在 solrconfig xml 中配置如下
  • lib.dom.ts 文件中最新的 typescript 重大更改

    在spec ts中例如 Dom spec ts describe matchesSelector gt let result boolean let matchelement HTMLElement it Matches for the o
  • Laravel 异常队列最大尝试次数超出

    我创建了一个应用程序来向多个用户发送电子邮件 但在处理大量收件人时遇到问题 该错误出现在failed jobs table Illuminate Queue MaxAttemptsExceededException App Jobs ESe
  • 导航栏隐藏在 SwiftUI 中不起作用

    我有三观 我想隐藏第三个视图中的导航栏 即使我给 navigationBarHidden true 导航栏正在显示 我找不到我哪里做错了 我已在下面附上我的代码和生成的屏幕截图 Xcode 版本 11 1 struct ContentVie
  • 在退出脚本之前等待后台进程完成

    在退出脚本 TCL Bash 之前 如何确保所有后台进程已完成执行 我正在考虑将所有后台进程 pid 写入 pid 文件 然后最后 pgrep pidfile 以查看在退出之前是否有任何进程仍在运行 有一些更简单的方法可以做到这一点吗 TC
  • NetBeans 将选项卡导航移至右侧

    我见过很少有人这样使用它 我正在努力思考 如何将 NetBeans IDE 中打开文件的导航移动到通过侧面的工具栏进行导航 换句话说 我希望选项卡显示在 NetBeans 的右侧 而不是在文件之间水平导航 就像在浏览器中一样 有人可以解释一
  • Apple AirLocation 演示应用程序测距不显示信标

    我有 3 个 Estimote 信标 可以通过 App store Estimate App 看到 现在我正在尝试运行 Apple 演示应用程序 AirLocation空中定位 https developer apple com libra
  • 如何在 Apache Camel 中定义通过 ref 抛出的异常

    必须在 XML 中定义的骆驼路由中抛出异常 成立throwExceptionCamel 2 3 中的声明如下所示
  • CakePHP hasOne/belongsTo 模型关系

    我有几个模型正在尝试关联 一种模型是Item 一个是Slide 另一个是Asset 项目下方有多个幻灯片 资产基本上是已上传的文件 图像 mp3 等 幻灯片是显示资产的位置 每张幻灯片都有一个资产 但给定的资产可能属于多张幻灯片 一张幻灯片
  • 如何在 Node JS 应用程序中顺序启动两个命令

    我使用 mocha chai 为我的 Node js 应用程序编写了一些单元测试 我想通过package json文件的scripts属性依次启动node JS服务器和测试套件 我的节点版本是6 9 4 我的 package json 中的
  • 如何在 Selenium for Python 上使用 XPATH 语法选择元素?

    考虑以下 HTML div div a class click abc a div div 我想单击 abc 但包装 div 可能会改变 所以 driver get element by xpath div id a div a class
  • sqlalchemy 插入或更新的简单方法?

    我有一系列新对象 它们看起来都类似于 Foo pk col1 x pk col2 y val bar 其中一些是存在的 Foo 即只有 val 与数据库中的行不同 并且应该生成更新查询 其他人应该生成插入 我可以想到几种方法来做到这一点 最
  • 如何创建包含多列MD5的GENERATED列?

    我尝试在 PostgreSQL 14 3 中添加下表 CREATE TABLE client cache id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY request VARCHAR