postgresql 从表中选择多个列,但按始终唯一的列分组

6g8kf2rb  于 2023-03-01  发布在  PostgreSQL
关注(0)|答案(2)|浏览(139)

在UI中,我有一个表,其中显示了按shipday分组的数据,shipday是一周中的几天。为了在hasura中做到这一点,我创建了一个PostgreSQL视图-

CREATE
OR REPLACE VIEW "public"."view_shipday" AS
SELECT
  shipdata.shipday,
  count(*) AS count,
  sum(shipdata.delivered) AS delivered,
  sum(shipdata.transit) AS transit,
  sum(shipdata.refused) AS refused,
  sum(shipdata.undeliverable) AS undeliverable,
  sum((shipdata.undeliverable + shipdata.refused)) AS total_exceptions
FROM
  shipdata
GROUP BY
  shipdata.shipday;

现在在UI上,我有两个过滤器carriershipdate,当用户选择像shipdatecarrier或两者的过滤器时,我想通过选择shipday的过滤器对数据进行分组,但我希望shipday总是唯一的(这很重要)。

CREATE
OR REPLACE VIEW "public"."view_shipday_and_filter" AS
SELECT
  shipdata.shipday,
  date(shipdata.shipdate),
  shipdata.carrier,
  count(*) AS count,
  sum(shipdata.delivered) AS delivered,
  sum(shipdata.transit) AS transit,
  sum(shipdata.refused) AS refused,
  sum(shipdata.undeliverable) AS undeliverable,
  sum((shipdata.undeliverable + shipdata.refused)) AS total_exceptions
FROM
  shipdata
GROUP BY
  shipdata.shipday,
  date(shipdata.shipdate),
  shipdata.carrier;

AFAIK hasura不允许对他们的graphql查询进行分组。我不想在客户端进行分组,因为数据量非常大,会降低应用程序的速度。因此,我想在数据库中创建一个或多个(如果需要)视图,这些视图将对处理上述情况的数据进行分组,以便shipday始终保持唯一。如果有其他选择,以实现这一点,而不创建视图,我也开放。

rxztt3cl

rxztt3cl1#

查询视图和运行定义视图的查询在性能上没有区别。事实上,PostgreSQL在运行查询时会用视图的定义替换视图。
您可以在问题的末尾使用视图,并向使用视图的查询添加额外的GROUP BY和求和,但这会使视图中的GROUP BY变得毫无意义,实际上会使查询变慢。
我的意见是,在这种情况下使用视图没有任何好处,因为过滤条件需要在分组之前应用,所以唯一的选择是直接查询shipdata,然后在应用查询中进行分组和求和。
您对此只字未提,但如果问题的一部分是此查询的性能太慢,则必须使用视图以外的其他工具。在这种情况下,可以选择使用通过“部分聚集”查询定义的 * 实体化视图 *,并在应用程序查询中执行最终过滤和分组。预聚集的实体化视图将小于基表。缺点是当shipdata中的数据发生变化时,物化视图也不会发生变化,因此您必须定期对物化视图进行REFRESH,并在两者之间使用稍微陈旧的数据。

n8ghc7c1

n8ghc7c12#

要获取 * 未筛选 * 发货日报告,您必须使用此查询(请参阅下面的示例数据)

select shipday, count(*)
from shipday
group by 1 order by 1;

shipday|count|
-------+-----+
      1|    2|
      2|    1|

要获得带有 * 筛选器 * 的报告,例如carrier = 'a',必须添加where predicate ,但仍按shipday分组

select shipday, count(*)
from shipday
where carrier = 'a'
group by 1 order by 1;
shipday|count|
-------+-----+
      1|    1|
      2|    1|
  • AFAIK不可能在PostgreSQL的视图中获取这两个查询。您需要其他RDBMS提供的称为参数化视图的功能。*

无论如何,您可以使用一个函数来优雅地覆盖此特性。

create or replace function select_shipday(p_carrier varchar(10) default null)
returns table (shipday int, cnt int) language sql as $$
    select shipday, count(*) cnt
    from shipday
    where carrier = p_carrier or p_carrier is null
   group by 1;
$$;

该函数获取一个参数来过滤carrier(如果定义),默认值是获取所有载波。
样本调用

-- all carriers
select * from select_shipday();
-- only carrier a
select * from select_shipday('a');

这当然是最简单的示例,但希望您了解如何为更高级的过滤器添加其他参数或其他函数。
此外,您可能希望在函数中添加ifthen逻辑,并为不同类型的过滤器定义专用查询。
样本数据

create table shipday as
select * from (values 
(1, 'a'),
(1, 'b'),
(2, 'a')
) tab (shipday, carrier)

相关问题