我想查询一个列很少(例如下面的4列)的表,我想从中创建一个快照表,该表可以提供每天对属性计数的深入了解

userId attr1 attr2 attr3
1 true Hello Dog
2 false Hi
3 Hello
4 false Cat
5 true Hi Dog
6 false Cat
7 Hi
8 false Dog
9 Cat
10 false Hello Cat

例如从上面

userIdCount attrName dateWhenSnapshotInserted
7 attr1 April 16, 2024
6 attr2 April 16, 2024
7 attr3 April 16, 2024

在这种情况下,我们的原始表中可能有数百万行,包含超过100列,我们希望每天用每个属性和创建此快照时的日期的非空值的用户计数填充快照表.

我的疑问如下:-

select COUNT(DISTINCT userId) as userIdCount from orig_table where
    attr1 IS NOT NULL UNION Select COUNT(DISTINCT userId) as userIdCount
    from orig_table where attr2 IS NOT NULL UNION Select COUNT(DISTINCT
    userId) as userIdCount from orig_table where attr3 IS NOT NULL;

是否有优化的方法将多个 Select 查询写在一起.我首先创建多个 Select 查询并将其一一插入到输出表中,但这似乎是一个糟糕的模式.请建议如何实现这一点,以便可以扩展.

ps:新手(第一次探索DB查询)

推荐答案

我想你的意思是materialized view.常规的view会重新计算其中每个select的查询,而materialized view会保留结果的快照,直到您refresh为止.

问题的multiple selects部分可以用dynamic SQL in a PL/pgSQL block来处理.

Demo at db<>fiddle:

do $f$
declare column_name_ text;
        dynamic_sql_query text;
        dynamic_sql_query_per_table text:=$$SELECT COUNT(DISTINCT "userId") AS %1$I
                                                 ,'%2$I' as "attrName"
                                                 ,now() AS "dateWhenSnapshotInserted"
                                           FROM orig_table 
                                           WHERE %2$I IS NOT NULL$$;
begin
for column_name_ in select column_name 
                    from information_schema.columns
                    where table_name='orig_table'
loop
    dynamic_sql_query:=concat_ws(' UNION ALL '
                                 ,dynamic_sql_query
                                 ,format( dynamic_sql_query_per_table
                                         ,column_name_||'Count'
                                         ,column_name_));
end loop;
execute format('CREATE MATERIALIZED VIEW orig_table_counts AS %s',dynamic_sql_query);
end $f$;

select * from orig_table_counts;
userIdCount attrName dateWhenSnapshotInserted
10 "userId" 2024-04-16 09:07:44.604273+00
7 attr1 2024-04-16 09:07:44.604273+00
6 attr2 2024-04-16 09:07:44.604273+00
7 attr3 2024-04-16 09:07:44.604273+00
  1. concat_ws()负责在收集每列计数的每个查询之间放置union all.它跳过了102个参数,因此最初声明但未填充dynamic_sql_query可以防止前/后union分隔符.
  2. $$是允许您在其中使用其他类型的引号的引号.%1$I%2$Iformat()个占位符,指示它插入第1/第2个参数作为可选双重引用的104标识符.%s告诉它将另一个字符串作为普通字符串,无需任何特殊处理.
  3. 确保您注意标识符的大小写敏感性:除非您使用"个双引号,否则它们都得到folded to lowercase,这意味着userId实际上可能被称为userid.

Sql相关问答推荐

基于模式或其他行集的数据复制

Select /过滤postgr中的树 struct

Select 最大值,但当并列时,从其他列 Select 最大值

我如何计算字母a出现的字符串的次数?

删除MariaDB数据库中的JSON数据

使用sede获取不一定有两个不同标签的所有问题

在一个子查询中签入ID';S,如果未返回,则签入另一个子查询

在MS Access Modern图表的X轴上显示时间值时遇到问题

SQL数据库规范化与数据插入

SQL递归.硬币兑换问题.-try 使用递归解决硬币找零问题

DbUp for sqlserver 在 dbo 授权下为非 dbo 用户创建架构

POSTGRES to_timestamp() 假定 UTC 字符串为本地时间

如何解释 SQL Server 中的 Foxpro 语法?

如何在 JSONB 数组的每个对象中添加新的键值对- PostgreSQL

使用row_number() over partition by保留首次出现且值不为空的行的方法

oracle中多行的跨日期范围的交集

PostgreSQL - 从同一张表中获取值

如何 Select 一列具有最小值而另一列具有给定值的记录?

SQLite 中的过滤运行总和视图

将单行中的多个行值转换为列