【问题标题】:PostgreSQL generating missing records and group them with source tablePostgreSQL 生成丢失的记录并将它们与源表分组
【发布时间】:2021-08-24 06:16:26
【问题描述】:

我正在创建一个 PostgreSQL 查询,我希望自动填写每一天的缺失记录。

我突然想到,我可以生成一个包含零值的表,然后将源表连接到它。

所以我创建了这个查询,但结果仍然不包含丢失的天数,只包含源数据库表中的现有记录。例如,缺少来自“2021-08-01 00:00:00”、“2021-08-07 00:00:00”或“2021-08-08 00:00:00”的记录。

SELECT
  s."Date",
  s."PowerOn",
  s."Idle",
  s."Run",
  CONCAT_WS('%', ROUND(NULLIF(s."Run"::numeric, 0) / NULLIF(s."PowerOn"::numeric, 0) * 100, 2), '') As "Effectivity"
FROM (
    SELECT d."Date", bigint '0' AS "PowerOn", bigint '0' AS "Idle", bigint '0' AS "Run", text '0 %' AS "Effectivity" 
    FROM (
        SELECT generate_series(timestamp '2021-08-01 00:00:00'
                        , NOW()
                        , interval  '1 day')::timestamp
) d("Date")) f
JOIN "Absolute_OEE" s ON s."Machine" = 'Machine01'
WHERE
  s."Date" > '2021-08-01 00:00:00'
GROUP BY s."Date",s."PowerOn", s."Idle", s."Run"
ORDER BY s."Date"

结果:

您能否告诉我如何对记录进行分组并为未记录的日期添加零值?

感谢您的建议和提示。

【问题讨论】:

  • 我会尝试生成仅包含日期的日期系列,并使用真实数据生成 OUTER JOIN - 这将使用 NULL 值填充缺失的数据,例如 SELECT generateseries(...) AS some_name LEFT OUTER JOIN your_table ON ...
  • 与你的问题无关,但是:你真的应该避免那些可怕的引用标识符。他们的麻烦比他们的价值要多得多。 wiki.postgresql.org/wiki/…

标签: sql postgresql join


【解决方案1】:

您可以使用 LEFT JOIN 和 COALESCE

SELECT
  d."Date",
  coalesce(s."PowerOn", bigint '0') AS "PowerOn",
  coalesce(s."Idle", bigint '0') AS "Idle",
  coalesce(s."Run", bigint '0') AS "Run",
  CONCAT_WS('%', ROUND(NULLIF(coalesce(s."Run", bigint '0')::numeric, 0) / NULLIF(coalesce(s."PowerOn", bigint '0')::numeric, 0) * 100, 2), '') As "Effectivity"
FROM (
     SELECT generate_series(timestamp '2021-08-01 00:00:00'
                     , NOW()
                     , interval  '1 day')::timestamp
     ) d
LEFT JOIN "Absolute_OEE" s ON d."Date"= s."Date" 
   AND s."Machine" = 'Machine01'
   AND s."Date" > '2021-08-01 00:00:00' 
GROUP BY  d."Date",
  coalesce(s."PowerOn", bigint '0'),
  coalesce(s."Idle", bigint '0'),
  coalesce(s."Run", bigint '0')
ORDER BY d."Date"

【讨论】:

  • 感谢您的回复。效果很好!
【解决方案2】:

只需使用left join,示例如下:

with base_data as (
select 
    generate_series(timestamp '2021-08-01 00:00:00', now(), interval  '1 day')::date as the_date,
    0 as col
)
,your_real_table as ( 
select
    the_date,
    count(1) as col
from
    table_name
where
    the_date >= '2021-08-01'::date 
group by
    the_date
)
select
    b.the_date,
    coalesce(r.col,b.col) as col
from
    base_data b
left join
    your_real_table r on b.the_date = r.the_date
order by
    b.the_date

【讨论】:

    【解决方案3】:

    我认为您的 JOIN 不正确...您得到的是笛卡尔积,然后您需要使用 GROUP BY 将其删除。

    进行以下更改

    • 给 generate_series() 列一个别名,例如选择generate_series(...)::timestamp AS spine
    • 将 JOIN 子句更改为 LEFT JOIN,例如`LEFT JOIN "Absolute_OEE" s ON s."Date" = f.spine
    • 那么您将不再需要 GROUP BY

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      相关资源
      最近更新 更多