当前位置: 首页 > 知识库问答 >
问题:

计算一行中为空的属性的数量

公冶才
2023-03-14

我想向表中添加一个新列来记录每个元组(行)值为空的属性的数量。如何使用SQL来获取数字?

例如,如果元组是这样的:

Name | Age | Sex
-----+-----+-----
Blice| 100 | null

我想将元组更新为:

Name | Age | Sex | nNULL
-----+-----+-----+--------
Blice| 100 | null|  1

另外,因为我正在编写PL/pgSQL函数,并且表名是从参数获取的,所以我事先不知道表的模式。这意味着我需要用输入表名更新表。有人知道怎么做吗?

共有3个答案

单于钊
2023-03-14

这是 @winged Panther 根据请求发布的内容的审核版本。

该函数将具有给定名称的列添加到调用角色具有必要权限的任何现有表中:

CREATE OR REPLACE FUNCTION f_add_null_count(_tbl regclass, _newcol text)
  RETURNS void AS
$func$
BEGIN
   -- add new col
   EXECUTE format('ALTER TABLE %s ADD COLUMN %I smallint', _tbl, _newcol);

   -- update new col with dynamic count of nulls
   EXECUTE (
      SELECT format('UPDATE %s SET %I = (', _tbl, _newcol)  -- regclass used as text
          || string_agg(quote_ident(attname), ' IS NULL)::int + (')
          || ' IS NULL)::int'
      FROM   pg_catalog.pg_attribute
      WHERE  attnum > 0
      AND    NOT attisdropped
      AND    attrelid = _tbl  -- regclass used as OID
      AND    attname <> _newcol  -- no escaping here, it's the *text*!
      );
END
$func$  LANGUAGE plpgsql;

SQL小提琴演示。

    < li >使用< code>%I或< code>quote_ident()转换为< code>regclass、< code>format()整理标识符。我在示例中使用了所有三种技术,每一种恰好都是使用它们的最佳选择。更多信息请点击此处: < ul > < li >作为PostgreSQL函数参数的表名

我用粗体格式化了相关的代码片段。

> < li>

我的查询基于< code > pg _ catalog . pg _ attribute ,但这是一个有利弊的可选决定。使我的查询更简单更快,因为我可以使用表的OID。相关:

  • 如何检查给定模式中是否存在表
  • 在PostgreSQL中选择具有特定列名的列

您必须将新添加的列从计数中排除,否则计数将减一。

使用数据类型 smallint 进行计数,因为表中不能超过 1600 列。

我不使用变量,而是直接执行< code>SELECT语句的结果。在plpgsql中,赋值是比较昂贵的。不过,没什么大不了的。也是品味和风格的问题。

我习惯在参数和变量前面加上下划线(_tbl),以排除变量和列名之间的歧义。

魏成济
2023-03-14

在Postgres中,您可以将其表示为:

select t.*,
       ((name is null)::int +
        (age is null)::int +
        (sex is null)::int
       ) as numnulls
from table t;

为了在未知表上实现这一点,您需要使用动态SQL并获取列列表(例如从information_schema.columns))。

龚鸿雪
2023-03-14

可能不拼写列。将列取消透视为行并计数。

聚合函数的计数(

适用于具有任意数量的任何数据类型的列的任何表。

在内置JSON函数的Postgres 9.3中:

SELECT *, (SELECT count(*) - count(v)
           FROM json_each_text(row_to_json(t)) x(k,v)) AS ct_nulls
FROM   tbl t;

什么是x(k, v)

json_each_text()返回一组有两列的行。默认列名是keyvalue,可以在我链接的手册中看到。我提供了表和列别名,因此我们不必依赖默认名称。第二列名为v

或者,在至少 8.3 以来的任何 Postgres 版本中,安装了额外的模块 hstore,甚至更短,更快:

SELECT *,  (SELECT count(*) - count(v) FROM svals(hstore(t)) v) AS ct_nulls
FROM   tbl t;

这个更简单的版本只返回一组单个值。我只提供了一个简单的别名v,它自动被视为表和列别名。

    < li >在Postgres数据库中的多个模式上安装hstore的最佳方法是什么?

由于附加列在功能上是依赖的,我会考虑根本不在表中持久化它。不如像上面演示的那样实时计算它,或者创建一个具有多态输入类型的小函数:

CREATE OR REPLACE FUNCTION f_ct_nulls(_row anyelement)
  RETURNS int  LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
'SELECT (count(*) - count(v))::int FROM svals(hstore(_row)) v';

(< code >并行安全仅适用于Postgres 9.6或更高版本。)

然后:

SELECT *, f_ct_nulls(t) AS ct_nulls
FROM   tbl t;

您可以将其包装到视图中...

数据库

这也应该回答你的第二个问题:

…表名是从参数获取的,我事先不知道表的模式。这意味着我需要用输入表名更新表。

 类似资料:
  • 问题内容: 我试图使它具有包装变量的属性。 为了符合要求,我需要使用来包装属性。不幸的是,我不能将其应用于计算的属性,因为我使用了这些值。 我该如何运作?我该怎么做才能达到目的? 问题答案: 更新:使用EnclosingSelf下标,可以做到! 奇迹般有效!

  • 问题内容: 在Swift WWDC简介会话中,展示了一个只读属性: 选择上述方法而不是使用方法有什么含义: 在我看来,您选择只读计算属性的最明显原因是: 语义 -在此示例中,将其作为类的属性而不是其执行的操作是有意义的。 简短明了 -避免在获取值时使用空括号。 显然,上面的示例过于简单,但是否有其他充分的理由选择一个?例如,是否有一些功能或属性的功能可以指导您决定使用哪种功能? 注意:乍看之下,这

  • 本文向大家介绍Vue计算属性的使用,包括了Vue计算属性的使用的使用技巧和注意事项,需要的朋友参考一下 我们都知道在Vue构造函数的参数对象中有一个【data】属性,该属性值是一个对象,该对象是对数据的代理,是一个键值对并且时刻与页面表现是一致的,但是这里面只能是简单的键值对,不能拥有业务逻辑,并且由于【data】中的属性属于同一个生命周期,所以如果我们需要某一个属性是依赖于另外一个属性时,在【d

  • 主要内容:实例 1,实例 2,computed vs methods,实例 3,computed setter,实例 4计算属性关键词: computed。 计算属性在处理一些复杂逻辑时是很有用的。 可以看下以下反转字符串的例子: 实例 1 <div id="app"> {{ message.split('').reverse().join('') }} </div> 实例 1 中模板变的很复杂起来,也不容易看懂理解。 接下来我们看看使用了计算属性的实例: 实例 2 <div id="app">

  • 主要内容:实例 1,实例 2,computed vs methods,实例 3,computed setter,实例 4计算属性关键词: computed。 计算属性在处理一些复杂逻辑时是很有用的。 可以看下以下反转字符串的例子: 实例 1 <div id="app"> {{ message.split('').reverse().join('') }} </div> 实例 1 中模板变的很复杂起来,也不容易看懂理解。 接下来我们看看使用了计算属性的实例: 实例 2 <!DOCTYPE html

  • 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如: <div id="example"> {{ message.split('').reverse().join('') }} </div> 所以,对于任何复杂逻辑,你都应当使用计算属性。在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量messa