如何包含时间跨度内多个分组的缺失数据?

2024-04-21

我在下面引用了查询,其中按教师、学习年月和过去 12 个月(包括当月)的房间对学习计数进行分组。我得到的结果是正确的,但是,我想在数据丢失时包含计数为零的行。

我查看了其他几个相关的帖子,但无法获得所需的输出:

  • Postgres - 如何返回缺失数据计数为 0 的行? https://stackoverflow.com/questions/346132/postgres-how-to-return-rows-with-0-count-for-missing-data/15733103#15733103
  • Postgresql 组月明智地缺失值 https://stackoverflow.com/questions/24156202/postgresql-group-month-wise-with-missing-values/24165871#24165871
  • Rails+Postgres 中按任意时间间隔计算记录的最佳方法 https://stackoverflow.com/questions/15576794/best-way-to-count-records-by-arbitrary-time-intervals-in-railspostgres/15577413#15577413

这是查询:

SELECT
    upper(trim(t.full_name))               AS teacher
  , date_trunc('month', s.study_dt)::date  AS study_month
  , r.room_code                            AS room
  , COUNT(1)                               AS study_count
FROM
  studies                           AS s
  LEFT OUTER JOIN rooms             AS r   ON r.id = s.room_id
  LEFT OUTER JOIN teacher_contacts  AS tc  ON tc.id = s.teacher_contact_id
  LEFT OUTER JOIN teachers          AS t   ON t.id = tc.teacher_id 
WHERE
  s.study_dt BETWEEN now() - interval '13 month' AND now()
  AND s.study_dt IS NOT NULL
GROUP BY
    teacher
  , study_month
  , room
ORDER BY 
    teacher  
  , study_month
  , room;

我得到的输出:

"teacher","study_month","room","study_count"
"DOE, JOHN","2015-07-01","A1",1
"DOE, JOHN","2015-12-01","A2",1
"DOE, JOHN","2016-01-01","B1",1
"SIMPSON, HOMER","2016-05-01","B2",3
"MOUSE, MICKEY","2015-08-01","A2",1
"MOUSE, MICKEY","2015-11-01","B1",1
"MOUSE, MICKEY","2015-11-01","B2",2

但我希望为所有缺失的年月和房间组合显示 0 计数。例如(仅第一排,共有 4 个房间:A1, A2, B1, B2):

"teacher","study_month","room","study_count"
"DOE, JOHN","2015-07-01","A1",1
"DOE, JOHN","2015-07-01","A2",0
"DOE, JOHN","2015-07-01","B1",0
"DOE, JOHN","2015-07-01","B2",0
...
"DOE, JOHN","2015-12-01","A1",1
"DOE, JOHN","2015-12-01","A2",0
"DOE, JOHN","2015-12-01","B1",0
"DOE, JOHN","2015-12-01","B2",0
...

为了获得丢失的年月,我尝试使用时间序列进行左外连接并加入time_range.year_month = study_month,但没有成功。

SELECT date_trunc('month', time_range)::date AS year_month
FROM generate_series(now() - interval '13 month', now() ,'1 month') AS time_range 

所以,我想知道如何“填补空白”

a) 年月和房间,并且作为奖励: b) 只是一年一个月。

这样做的原因是数据集将被输入到一个数据透视库中,我们可以得到类似于以下的输出(无法直接在 PG 中执行此操作):

teacher,room,2015-07,...,2015-12,...,2016-07,total
"DOE, JOHN",A1,1,...,1,...,0,2
"DOE, JOHN",A2,0,...,0,...,0,0
...and so on...

基于一些假设(问题中的含糊之处)我建议:

SELECT upper(trim(t.full_name)) AS teacher
     , m.study_month
     , r.room_code              AS room
     , count(s.room_id)         AS study_count

FROM   teachers t
CROSS  JOIN generate_series(date_trunc('month', now() - interval '12 month')  -- 12!
                          , date_trunc('month', now())
                          , interval '1 month') m(study_month)
CROSS  JOIN rooms r
LEFT   JOIN (                                                  -- parentheses!
          studies s
   JOIN   teacher_contacts tc ON tc.id = s.teacher_contact_id  -- INNER JOIN!
   ) ON tc.teacher_id = t.id
    AND s.study_dt >= m.study_month
    AND s.study_dt <  m.study_month + interval '1 month'      -- sargable!
    AND s.room_id = r.id
GROUP  BY t.id, m.study_month, r.id  -- id is PK of respective tables
ORDER  BY t.id, m.study_month, r.id;

主要观点

  • 构建所有所需组合的网格CROSS JOIN。进而LEFT JOIN到现有行。有关的:

    • array_agg group by 和 null https://stackoverflow.com/questions/22443882/array-agg-group-by-and-null/22480876#22480876
    • 获取上周创建和删除的条目 https://stackoverflow.com/questions/29371305/get-created-as-well-as-deleted-entries-of-last-week/29375290#29375290
  • 在你的例子中,它是几个表的联接,所以我在FROM列出至LEFT JOIN to the result of INNER JOIN括号内。 这将是不正确 to LEFT JOIN分别到每个表,因为您将包括部分匹配的命中并获得可能不正确的计数。

  • 假设参照完整性直接使用 PK 列,我们不需要包括rooms and teachers第二次在左侧。但我们仍然有两个表的联接(studies and teacher_contacts)。的作用teacher_contacts我不清楚。通常情况下,我期望之间存在关系studies and teachers直接地。可能会进一步简化...

  • 我们需要计算左侧的非空列以获得所需的计数。喜欢count(s.room_id)

  • 为了让大表保持快速,请确保您的谓词是sargable https://en.wiktionary.org/wiki/sargable。并添加匹配indexes.

  • 专栏teacher很难(可靠)独特。使用唯一的 ID 进行操作,最好是 PK(也更快、更简单)。我还在用teacher使输出符合您想要的结果。包含唯一 ID 可能是明智之举,因为名称可能重复。

  • 你要:

    过去 12 个月(包括当月)。

    所以从date_trunc('month', now() - interval '12 month'(不是 13)。这已经四舍五入了开始并执行您想要的操作 - 比您的原始查询更准确。


由于您提到性能缓慢,根据实际的表定义和数据分布,可能会更快先聚合后加入,就像这个相关的答案一样:

  • Postgres - 如何返回缺失数据计数为 0 的行? https://stackoverflow.com/questions/346132/postgres-how-to-return-rows-with-0-count-for-missing-data/15733103#comment64041705_15733103
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何包含时间跨度内多个分组的缺失数据? 的相关文章

  • sql/mysql 过滤器仅包含最大值

    我有一个像这样的结果集 ID name myvalue 1 A1 22 2 A2 22 3 A3 21 4 A4 33 5 A5 33 6 A6 10 7 A7 10 8 A8 10 9 A9 5 我想要的是仅包含包含可用的最高 myval
  • 无法安装 psycopg2 Ubuntu

    试图为 django 项目准备好服务器 但我在设置 postgres 时遇到了一些问题 我正在遵循本指南 https jee appy blogspot com 2017 01 deply django with nginx html ht
  • 触发器以捕获服务器中的架构更改

    是否可以实现类似以下触发器的东西 CREATE TRIGGER tr AU ddl All Server ON DATABASE WITH EXECUTE AS self FOR DDL DATABASE LEVEL EVENTS AS D
  • 如何使用flyway将数据从一个DB迁移到另一个DB?

    我在不同的服务器上有两个 postgreSql DB 比如说 A 和 B 我可以使用 Flyway 一些如何将所有数据从 DB A 复制到新设置且为空的 B 如果有人指出我正确的方向和工具 这将很有帮助 要求是通过某种工具自动化将数据从一个
  • 查找一列中具有相同值而另一列中具有其他值的行?

    我有一个 PostgreSQL 数据库 将用户存储在users他们参与的表格和对话conversation桌子 由于每个用户可以参与多个对话 并且每个对话可以涉及多个用户 因此我有一个conversation user链接表来跟踪哪些用户正
  • Postgres - 这是在布尔列上创建部分索引的正确方法吗?

    我有下表 CREATE TABLE recipemetadata Lots of columns diet glutenfree boolean NOT NULL 大多数每一行都会被设置为FALSE除非有人想出一些席卷全国的疯狂新无麸质饮食
  • 通过“SELECT”命令选择每组的前两条记录的最佳方法是什么?

    例如我有下表 id group data 1 1 aaa 2 1 aaa 3 2 aaa 4 2 aaa 5 2 aaa 6 3 aaa 7 3 aaa 8 3 aaa 通过 SELECT 命令选择每组的前两条记录的最佳方法是什么 如果没有
  • 删除 DB 但不删除 *.mdf / *.ldf

    我正在尝试自动化分离和删除数据库的过程 通过 VBS objshell run 如果我手动使用 SSMS 分离和删除我可以将数据库文件复制到另一个位置 但是如果我使用 sqlcmd U sa P MyPassword S local Q A
  • 小数除以小数并得到零

    为什么当我这样做时 select CAST 1 AS DECIMAL 38 28 CAST 1625625 AS DECIMAL 38 28 我得到 0 吗 但是当我得到 0 时 select CAST 1 AS DECIMAL 20 10
  • 在调用存储过程 Sql Server 2008 时使用嵌套存储过程结果

    是否可以在另一个存储过程中使用一个存储过程的结果 I e CREATE PROCEDURE dbo Proc1 ID INT mfgID INT DealerID INT AS BEGIN DECLARE Proc1Result UserD
  • 当添加列较少时追加到现有 SQLite 表,而不将数据库读入 R

    是否有一些简单的方法 无论是在 SQL 端还是在 R 端 将 data frame 附加到具有更多列的现有表 缺失的列应该用 NA 填充 如果它能够优雅地处理比表 1 列数更多的表 2 那么会加分吗 library RSQLite Crea
  • SQL查询多行变成单行

    有什么方法可以将通常返回具有相同值的多行的 SQL 查询更改为单行吗 例如 如果我现有的查询返回以下内容 ColA ColB 1 AA 1 BB 1 CC 2 AA 3 AA 我可以将查询更改为仅返回 3 行 并将 1 的第二个和第三个结果
  • 如何授予用户访问 SQL Server 中的 sys.master_files 的权限?

    我需要授予数据库用户读取权限sys master files桌子 我怎样才能做到这一点 目前用户拥有以下权限 Calling SELECT on sys master files返回空结果 我还使用以下命令测试了相同的查询sa用户按预期工作
  • Oracle中如何转义单引号? [复制]

    这个问题在这里已经有答案了 我有一列包含某些存储为文本字符串的表达式 其中包括单个引号 例如 错过的交易 包括引号 发生这种情况时如何使用 where 子句 select from table where reason missed tra
  • SQL 解析键值字符串

    我有一个像这样的逗号分隔字符串 key1 value1 key2 value2 key3 value3 key1 value1 1 key2 value2 1 key3 value3 1 我想将它解析成一个如下所示的表 Key1 Key2
  • 寻找多列索引的最佳顺序

    假设我有一个包含两个索引的表 一个位于 a 列 一个位于 a b 和 c 列 我注意到 根据索引定义中列的顺序 MySQL 可能最终使用单列索引而不是多列索引 即使多列索引中的所有三列都在 ON 中引用JOIN 的一部分 这有点引出了一个问
  • 获取MySql中重复行的列表

    我有一张这样的桌子 ID nachname vorname 1 john doe 2 john doe 3 jim doe 4 Michael Knight 我需要一个查询 该查询将从具有相同 nachname 和 vorname 的记录
  • 使用外部硬盘写入和存储 mysql 数据库

    我已经设置了 mysql 数据库在我的 Mac 上使用 java 和 eclipse 运行 它运行得很好 但现在我将生成大约 43 亿行数据 这将占用大约 64GB 的数据 我存储了大量的密钥和加密值 我有一个 1TB 外部我想用作存储位置
  • SQL:两个没有完整列匹配的表的并集

    我有一个table A其中有一组列A1 A2和一个具有一组列的 table bB1 B2 碰巧的是A2 B1但其余列不匹配 也不应该匹配 我想附加表格 所以我使用UNION ALL 对于不匹配的列 我使用null as COLUMN NAM
  • oracle日期序列?

    我有一个 oracle 数据库 我需要一个包含 2 年所有日期的表 例如来自01 01 2011 to 01 01 2013 首先我想到了一个序列 但显然唯一支持的类型是数字 所以现在我正在寻找一种有效的方法来做到这一点 欢呼骗局 如果您想

随机推荐