当列不存在时 Postgres 返回默认值

2024-01-27

我有一个查询,如果缺少某个列,我本质上需要一个后备值。我想知道我是否可以纯粹在查询中处理这个问题(而不是先探测并发送单独的查询。本质上我正在寻找相当于COALESCE处理缺失列的情况。

想象一下以下两张表。

T1
id | title | extra
1    A     | value

- and -

T2
id | title
1    A

我希望能够使用相同的查询从这些表中进行选择。

例如,如果 t2 实际上有一个“额外”列,我可以使用

 SELECT id,title, COALESCE(extra, 'default') as extra

但只有当列值为 NULL 时才有效,而当列完全丢失时则无效。

我更喜欢 SQL 版本,但我也可以接受 PLPGSQL 函数(其行为类似于 COALLESCE)。

SQL 纯粹主义者注意:我真的不想争论为什么我想在 SQL 中而不是在应用程序逻辑中执行此操作(或者为什么我不会将列永久添加到架构中),因此请将您的评论/答案限制为具体请求,而不是您对数据库“正确性”的看法或任何其他可能冒犯您的问题。


为什么罗文的黑客攻击 https://stackoverflow.com/a/18951791/939860工作(大部分)?

SELECT id, title
     , CASE WHEN extra_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN (
   SELECT EXISTS (
      SELECT FROM information_schema.columns 
      WHERE  table_name = 'tbl'
      AND    column_name = 'extra')
   ) AS extra(extra_exists)

正常情况下,它根本不起作用。 Postgres 解析 SQL 语句并抛出异常,如果any所涉及的列不存在。

诀窍是引入与相关列名同名的表名(或别名)。extra在这种情况下。每个表名都可以作为一个整体引用,这会导致整行作为类型返回record。由于每种类型都可以转换为text,我们可以将整个记录投射到text。这样,Postgres 就会接受有效的查询。

由于列名优先于表名,extra::text被解释为列tbl.extra如果该列存在。否则,它将默认返回表的整行extra- 这永远不会发生。

尝试选择不同的表别名extra亲自看看。

这是一无证黑客攻击,可能会破坏如果 Postgres 决定在未来版本中改变 SQL 字符串的解析和规划方式 - 尽管不太可能。

明确

If你决定至少使用这个使其明确.

表名本身并不唯一。名为“tbl”的表可以在同一数据库的多个模式中存在任意多次,这可能会导致非常混乱且完全错误的结果。你need另外提供模式名称:

SELECT id, title
     , CASE WHEN col_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN (
   SELECT EXISTS (
      SELECT FROM information_schema.columns 
      WHERE  table_schema = 'public'
      AND    table_name = 'tbl'
      AND    column_name = 'extra'
      ) AS col_exists
   ) extra;

Faster

由于这个查询很难移植到其他 RDBMS,我建议使用目录表pg_attribute https://www.postgresql.org/docs/current/catalog-pg-attribute.html而不是信息模式视图information_schema.columns。大约快10倍。

SELECT id, title
     , CASE WHEN col_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN (
   SELECT EXISTS (
      SELECT FROM pg_catalog.pg_attribute
      WHERE  attrelid = 'myschema.tbl'::regclass  -- schema-qualified!
      AND    attname  = 'extra'
      AND    NOT attisdropped    -- no dropped (dead) columns
      AND    attnum   > 0        -- no system columns
      )
   ) extra(col_exists);

还使用更方便、更安全地投射到regclass. See:

  • regclass 在 Postgresql 中意味着什么 https://stackoverflow.com/questions/13289107/what-does-regclass-signify-in-postgresql/13290020#13290020

您可以附加所需的别名来欺骗 Postgresany表,包括主表本身。您根本不需要加入另一个关系,这应该是最快的:

SELECT id, title
     , CASE WHEN EXISTS (SELECT FROM pg_catalog.pg_attribute
                         WHERE  attrelid = 'tbl'::regclass
                         AND    attname  = 'extra'
                         AND    NOT attisdropped
                         AND    attnum   > 0)
            THEN extra::text
            ELSE 'default' END AS extra
FROM tbl AS extra;

方便

您可以将存在性测试封装在一个简单的 SQL 函数中(一次),(几乎)到达您一直要求的函数:

CREATE OR REPLACE FUNCTION col_exists(_tbl regclass, _col text)
  RETURNS bool
  LANGUAGE sql STABLE AS
$func$
SELECT EXISTS (
   SELECT FROM pg_catalog.pg_attribute
   WHERE  attrelid = $1
   AND    attname  = $2
   AND    NOT attisdropped
   AND    attnum   > 0
   )
$func$;

COMMENT ON FUNCTION col_exists(regclass, text) IS
'Test for existence of a column. Returns TRUE / FALSE.
$1 .. exact table name (case sensitive!), optionally schema-qualified
$2 .. exact column name (case sensitive!)';

将查询简化为:

SELECT id, title
     , CASE WHEN col_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN col_exists('tbl', 'extra') AS extra(col_exists);

在这里使用具有附加关系的形式,因为事实证明使用该函数更快。

尽管如此,你只能得到文本表示具有任何这些查询的列。获得它并不那么简单实际类型.

基准

我在第 9.1 和 9.2 页上运行了 100k 行的快速基准测试,发现这些是最快的:

Fastest:

SELECT id, title
     , CASE WHEN EXISTS (SELECT FROM pg_catalog.pg_attribute
                         WHERE  attrelid = 'tbl'::regclass
                         AND    attname  = 'extra'
                         AND    NOT attisdropped
                         AND    attnum   > 0)
            THEN extra::text
            ELSE 'default' END AS extra
FROM   tbl AS extra;

第二快:

SELECT id, title
     , CASE WHEN col_exists THEN extra::text ELSE 'default' END AS extra
FROM   tbl
CROSS  JOIN col_exists('tbl', 'extra') AS extra(col_exists);

db<>fiddle
Old sqlfiddle http://www.sqlfiddle.com/#!12/dc1c2/5

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当列不存在时 Postgres 返回默认值 的相关文章

  • 错误关系不存在

    我得到了 error relation causes does not exist 我的节点应用程序出现错误 这种关系确实存在 我不确定问题出在哪里 我创建了该表 CREATE TABLE causes cause id bigint NO
  • 带有可变 WHERE 子句的批量 UPDATE 表

    我有一堆值对 foo1 bar1 foo2 bar2 我想做一堆更新 将 foo 列设置为 foo1 其中 bar 列为 bar1 我正在使用 psycopg2 在 Python 中执行此操作 我可以executemany与查询UPDATE
  • 更好地理解 SQL Server 中的架构

    就像标题一样 我还是一个SQLServer菜鸟 当我创建表 Mytable 时 数据库中显示 dbo Mytable 但有人能让我更好地理解模式吗 另外 在 Server 2008 TSQL 一书中 Itzik 说 在你的数据库中 表属于模
  • 为 PostgreSQL 查询选择正确的索引

    简化表 CREATE TABLE products product no integer PRIMARY KEY sales integer status varchar 16 category varchar 16 CREATE INDE
  • 如何用约束标记一大组“传递群”?

    在 NealB解决方案之后进行编辑 与以下解决方案相比 NealB的解决方案非常非常快任何另一个 https stackoverflow com q 18033115 answers and 提出了关于 添加约束以提高性能 的新问题 Nea
  • IIF(...) 不是公认的内置函数

    我正在尝试在 Microsoft SQL Server 2008 R2 中使用它 SET SomeVar SomeOtherVar IIF SomeBool value when true value when false 但我收到一个错误
  • 时间序列数据的自连接

    我需要一些帮助来完成我认为应该是相当简单的自连接查询 只需要将两条记录中匹配的开始时间和结束时间合并为一条记录 假设我的表中有以下内容 Time Event 08 00 Start 09 00 Stop 10 30 Start 10 45
  • 使用连接池后如何处理过多的并发连接?

    Scenario 假设您有一个拥有大量流量的网站或应用程序 即使使用数据库连接池 性能也会受到真正的打击 站点 应用程序甚至可能崩溃 因为并发连接太多 Question 人们有什么选择来处理这个问题 我的想法 我在想有这个问题的人可以创建多
  • 如何使用原始 SQL 查询实现搜索功能

    我正在创建一个由 CS50 的网络系列指导的应用程序 这要求我仅使用原始 SQL 查询而不是 ORM 我正在尝试创建一个搜索功能 用户可以在其中查找存储在数据库中的书籍列表 我希望他们能够查询 书籍 表中的 ISBN 标题 作者列 目前 它
  • Django 模型:默认日期时间未转换为 SQL CURRENT_TIMESTAMP

    我正在使用 Django 模型创建 PostgreSQL DB 我有一个 DateTimeField 我想将当前时间戳设置为默认值 我知道有多个消息来源建议如何做到这一点 但是 当我在 Django 之外检查数据库时 默认时间戳不会显示 我
  • SQL 标准是否允许函数名和括号之间有空格

    检查一些 RDBMS 我发现类似的事情 SELECT COUNT a SUM b FROM TABLE 允许 注意聚合函数和括号之间的空格 谁能提供一个指向 SQL 标准本身定义的指针 任何版本都可以 编辑 以上在postgres中工作 m
  • SQL查询查找具有特定数量关联的行

    使用 Postgres 我有一个架构conversations and conversationUsers Each conversation有很多conversationUsers 我希望能够找到具有确切指定数量的对话conversati
  • 没有提示指令的直连接中表的顺序是否会影响性能?

    所有基于 SQL 的 RDBMS 10 年前的版本 直接连接查询 没有提示指令 中的表顺序是否会对最佳性能和内存管理产生影响 听说最后一个join应该是最大的表 您的数据库的查询优化器如何处理这种情况 回答你的问题 是的 表的顺序在连接中有
  • 通过 C# SqlCommand 执行合并语句不起作用

    我正在第一次尝试使用临时表和MERGE语句通过更新 SQL 表SqlCommandC 中的对象 我正在开发的程序旨在首先将大量记录 最多 20k 导出到 Excel 电子表格中 然后 用户可以搜索并替换特定值 并根据需要更新任意多记录中的任
  • Ruby ActiveRecord 和 sql 元组支持

    ActiveRecord 是否支持 where 子句中的元组 假设底层数据库支持 结果 where 子句看起来像这样 where name address in John 123 Main St I tried Person where n
  • 向带有检查约束 SQL 的表添加列

    我想向表中添加一列 然后添加一个检查约束以确保其大于 0 我似乎无法让它在 oracle sl Developer 中运行 Alter TABLE store101 add column Base salary Number 7 2 con
  • MySQL“列计数与第 1 行的值计数不匹配”是什么意思

    这是我收到的消息 ER WRONG VALUE COUNT ON ROW 列计数与第 1 行的值计数不匹配 这是我的全部代码 我的错误在哪里 DROP TABLE student CREATE TABLE employee emp id I
  • 更改表添加列并在同一条件 IF 语句中更新新列

    我正在尝试添加列并在同一 if 语句中更新它 BEGIN TRAN IF NOT EXISTS SELECT 1 FROM sys columns WHERE Name N Code AND Object ID Object ID N Te
  • PostgreSQL:删除数据库但数据库仍然存在[重复]

    这个问题在这里已经有答案了 我是 PostgreSQL 的新手 我尝试着理解它 我熟悉数据库和MySQL 我正在尝试删除我创建的数据库 因为 psql 似乎忽略了我尝试通过 Django 推送的更改 当我执行时 l我得到以下回复 List
  • 多边形内的 SQL 地理点在 STIntersect 上不返回 true(但使用 Geometry 返回 true)

    我不想仅仅为了在 STIntersect 中返回 true 而将地理数据转换为几何图形 下面是 SQL 中的代码 DECLARE point GEOGRAPHY GEOGRAPHY Point 1 1 4326 DECLARE polygo

随机推荐

  • VBS 中的 MSGbox 根据变量值进行更新

    只是想知道我如何拥有一个 MSgbox 来显示不断变化的变量值 基本上 一个数字每次循环时都会添加一个 我想在不必打开一百万个窗口的 MSGbox 中显示它 解决方法是使用PopUp Set objShell WScript CreateO
  • 如何将值查询集的值追加到数组?

    我的观点 py from django db models import Count def test1 request states Loksabha objects values state distinct state terms L
  • Ionic 导航栏:标题未在 Android 设备上居中

    我对 Ionic 很陌生 但我已经喜欢它了 我想用nav bar所以我实现了以下index html
  • 编写不使用循环索引的 for 循环的 Pythonic 方法[重复]

    这个问题在这里已经有答案了 这与以下代码有关 该代码使用 for 循环生成一系列随机偏移量以供程序中其他地方使用 该 for 循环的索引未使用 这导致 Eclipse PyDev 将 有问题的 代码突出显示为警告 def RandomSam
  • 如何在 Actionscript 3 中将十六进制转换为十进制?

    如何在 Actionscript3 中将十六进制 字符串 转换为十进制 int Number int and uint类有toString 接受的方法radix作为参数 radix指定用于数字到字符串转换的数字基数 从 2 到 36 如果不
  • 如何从 DOM 中删除 element.nativeElement?

    我尝试了这样的方法 ViewChild draggable private draggableElement ElementRef this draggableElement nativeElement remove HTML div Bl
  • MVC3 ajax 将多个复选框值发送到控制器

    我正在尝试使用 MVC3 来完成以下任务 我有一个包含多个值的表 使用ajax我希望能够选择作为表一部分的删除复选框 对于任意数量的行 使用ajax将结果发布到控制器进行处理 我目前遇到的问题是我无法让控制器接受来自 ajax post 的
  • Websocket 因 1006 错误而断开连接,无原因

    我正在我的网页游戏中记录断开连接 似乎 75 的会话因代码 1001 正常 而断开连接 25 的会话因代码 1006 错误 而断开连接 https www rfc editor org rfc rfc6455 https www rfc e
  • 五个不同的 GAE 站点可以共享一个公共数据存储吗?

    除了特定站点的数据存储之外 您是否还可以在所有网站之间共享一个数据存储 比如连接到与主 MySQL 数据库不同的 MySQL 数据库 并不真地 两种解决方法 使用同一应用程序的五个 版本 而不是五个不同的应用程序 他们将共享相同的数据存储
  • 将 python django 项目 1.3 升级到 1.5

    目前我有一个使用 django 版本 1 3 的 python 项目在 Mountain Lion OS 上运行 现在我想将其升级到 django 1 5 但是当我把它放在尝试做的时候python manage py runserver我收
  • 具有 SFINAE 虚拟参数的不明确模板

    考虑一种需要验证类型的情况T与另一个模板g 可能是一些enable if表达式 例如 在另一个模板的虚拟参数内 如下所示 template
  • ConnectionString 属性尚未初始化

    我查看了不同论坛上的很多帖子 其他人也收到了同样的错误 大多数人表示他们没有正确引用 web config 文件中的连接字符串 或者他们在设置连接字符串之前尝试打开连接 好吧 如果对我来说是这种情况 那么它如何在两个不同的系统上工作 但在第
  • 如何在 CertCreate 自签名证书函数中指定密钥大小

    我正在使用该功能证书创建自签名证书 https msdn microsoft com en us library windows desktop aa376039 v vs 85 aspx生成证书 我需要指定密钥大小2048 我不知道如何提
  • javascript按索引号进行字符串分配怪癖

    a 12345 a 2 3 a 2 9 console log a gt 12345 到底是怎么回事 这个怪癖导致我痛苦地调试了1个小时 如何以明智的方式避免这种情况 不能使用方括号重写字符串中的各个字符 仅 getter 即读取 访问可用
  • Github 操作 `on` 中没有定义事件触发器

    我创建了一个管道 我想在每次推送任何分支时触发 有我的default yml name default on push branches jobs build runs on macOS latest steps uses actions
  • 模板类的 typedef?

    是否有可能typedef使用模板的长类型 例如 template
  • 反应本机要求不适用于图像源

    给出下面的代码 反应本机抱怨 Requiring unknown module images Foo png If you are sure the module is there try restarting the packager o
  • 在 Android 中使用 OpenCV 检测图像中的圆圈

    我正在开发一个安卓应用程序其中我必须检测现有图像上的圆圈 从图库浏览或从相机捕获 浏览 捕获的图像将显示在 ImageView 上 顺便说一句 我正在使用OpenCV Android 库我正确地编译了它 对我的 Android 应用程序有任
  • 我可以同时使用 SOAP Webservices 和 Spring MVC

    我有一个 Spring MVC 项目 我写了一段类似的代码 Controller RequestMapping CallBack WebService name NotificationToCP targetNamespace http S
  • 当列不存在时 Postgres 返回默认值

    我有一个查询 如果缺少某个列 我本质上需要一个后备值 我想知道我是否可以纯粹在查询中处理这个问题 而不是先探测并发送单独的查询 本质上我正在寻找相当于COALESCE处理缺失列的情况 想象一下以下两张表 T1 id title extra