复合类型数组上的 SUM 和 GROUP BY

Posted

技术标签:

【中文标题】复合类型数组上的 SUM 和 GROUP BY【英文标题】:SUM & GROUP BY on an array of composite type 【发布时间】:2015-03-27 21:55:55 【问题描述】:

我有一列包含复合类型 (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 ***\",13.4,\"2015-04-04 09:04:00\")"

预期结果:

总和(1.5 + 13.4) = 14.9

按 2015-04-03、2015-04-04 分组

【问题讨论】:

类型用双引号创建,表格不用? 是的,它们的创建方式如上所示 错误:在 "(" LINE 1: SELECT e.id, s.(st).stage_start_time::date AS day 或附近出现语法错误 现在应该修复了。左括号在我的更新中放错了位置。括号需要围绕完整的列名。 【参考方案1】:

由于缺少信息,假设当前 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
);

它也不会占用更多的磁盘空间,数组开销类似于表开销。只有附加索引需要更多空间。但是基表上的许多查询会更快,更新会很多便宜,而且一切都会变得更干净、更简单。

请勿将带引号和不带引号的大写字母与标识符混用。这很容易出错。尽可能使用不带引号的合法小写名称。

Are PostgreSQL column names case-sensitive?

查询将是:

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) 周围的括号(未嵌套列的列别名)。您需要这些来访问composite type (row type) 的元素。

为什么是LEFT JOIN LATERAL ... ON true

Call a set-returning function with an array argument multiple times

【讨论】:

我现在得到错误:列符号 .stage_distance 应用于类型 stage[],它不是复合类型 LINE 1:SELECT ("Stage_Information").Stage_Distance::date AS day,更新问题 @AlanMulligan:好的,这是一个复合类型的数组。解释为什么标题中有“数组”。需要更复杂的方法。你到底想计算什么?单个列或整个表的总和?请将您的 Postgres 版本添加到问题中。 我需要总结 Stage_Distance where id = 1 并选择 Stage_Start_Time where id = 1 group by Stage_Start_Time (day-month--year) 如果他们有意义的话 @AlanMulligan:您不能一次选择时间组。逻辑上自相矛盾。如果您觉得难以解释,请在您的问题中添加示例值和所需结果。

以上是关于复合类型数组上的 SUM 和 GROUP BY的主要内容,如果未能解决你的问题,请参考以下文章

Go语言 复合数据类型数组map

GO语言学习——复合数据类型 数组

C++数组,指针,引用以及三者的复合类型

Go语言入门篇-复合数据类型

一文了解 Go 的复合数据类型(数组切片 SliceMap)

数组字段上的唯一复合索引