SUM& GROUP BY在复合类型的数组上

时间:2015-03-27 21:55:55

标签: sql postgresql types aggregate-functions compositetype

我有一个复合类型(text, decimal, timestamp)数组的列作为数据类型。我想创建一个查询来汇总复合类型的双列的总和。此外,我想在日期时间的日期(日 - 月 - 年)执行一组。

有人能告诉我一个解释如何做到这一点的例子吗?

表和类型的定义:

create type stage as (
   Stage_Name        text,
   Stage_Distance    decimal,
   Stage_Start_Time  timestamp
);

CREATE TABLE "Event" (
  "Id" serial NOT NULL,
  "Location" text,
  "Date_Range" daterange,
  "Surface" text,
  "Stage_Information" stage[],
  CONSTRAINT "PK_Event" PRIMARY KEY ("Id")
);

示例数据

{"(Newtownards,1.5,\"2015-04-03 18:28:00\")"
,"(\"Bulls Brook\",13.4,\"2015-04-04 09:04:00\")"}

预期结果:

总和(1.5 + 13.4)= 14.9

分组到2015-04-03,2015-04-04

1 个答案:

答案 0 :(得分:3)

假设当前的Postgres版本为9.4缺乏信息。

正确的设计

首先,考虑一下database normalization。另外一个表而不是列"Stage_Information"通常是优秀的解决方案:

CREATE TABLE stage (
  stage_id  serial PRIMARY KEY
, event_id  int NOT NULL REFERENCES event
, name      text        -- possibly NOT NULL
, distance  numeric     -- possibly NOT NULL
, starttime timestamp   -- possibly NOT NULL
);

它也不会占用更多的磁盘空间,阵列开销与表开销类似。只有附加索引需要更多空间。但是基表上的许多查询会更快,而且更新会更便宜,而且一切都会更简洁。

不要将引用和不引用的大小写与您的标识符混合使用。这非常容易出错。如果可以,请专门使用不带引号,合法的小写名称。

然后查询将是:

SELECT e.id, s.starttime::date AS day
     , sum(s.distance) AS sum_distance
FROM   "Event" e
LEFT   JOIN stage s ON s.event_id = e.id
WHERE  e.id = 1
GROUP  BY 1, 2;

手头问题的解决方案

在坚持使用当前设计时,您需要unnest()数组将聚合函数应用于其元素。那么你需要分解复合值。使用LATERAL加入:

SELECT e.id, (s.st).stage_start_time::date AS day
     , sum((s.st).stage_distance) AS sum_distance
FROM   "Event" e
LEFT   JOIN LATERAL unnest(e."Stage_Information") s(st) ON true
WHERE  e.id = 1
GROUP  BY 1, 2;

请注意(s.st)周围的括号(unnested列的列别名)。您需要访问composite type (row type)的元素。

为什么LEFT JOIN LATERAL ... ON true