Sql 具有可变列的Postgres数据聚合

Sql 具有可变列的Postgres数据聚合,sql,database,postgresql,pivot,crosstab,Sql,Database,Postgresql,Pivot,Crosstab,我有一个包含时间日志信息的数据表 create table "time_records" ( "id" serial NOT NULL PRIMARY KEY, "start" timestamp not null, "end" timestamp not null, "duration" double precision not null, "project" varchar(255) not null, "case" integer not n

我有一个包含时间日志信息的数据表

create table "time_records" (
    "id" serial NOT NULL PRIMARY KEY,
    "start" timestamp not null,
    "end" timestamp not null,
    "duration" double precision not null,
    "project" varchar(255) not null,
    "case" integer not null,
    "title" text not null,
    "user" varchar(255) not null
);
以下是几行数据:

"id","start","end","duration","project","case","title","user"
"1","2014-02-01 11:54:00","2014-02-01 12:20:00","26.18","Project A","933","Something done here","John Smith"
"2","2014-02-02 12:34:00","2014-02-02 15:00:00","146","Project B","990","Something else done","Joshua Kehn"
"3","2014-02-02 17:57:00","2014-02-02 18:39:00","41.38","Project A","933","Another thing done","Bob Frank"
"4","2014-02-03 09:30:00","2014-02-03 11:41:00","131","Project A","983","iOS work","Joshua Kehn"
"5","2014-02-03 10:22:00","2014-02-03 13:29:00","187.7","Project C","966","Created views for things","Alice Swiss"
我可以从中提取一些零碎的信息。例如,在两个日期之间记录时间的每个项目或在两个日期之间工作的每个人的列表

我想要的是能够生成一个带有日期的报告,然后在顶部的每个项目中生成该项目记录的总时间

SELECT
    start::date,
    sum(duration / 60) as "time logged",
    project
FROM
    time_records
WHERE
    project = 'Project A'
GROUP BY
    start::date, project
ORDER BY
    start::date, project;
但是,我希望输出上有多个列,因此以某种方式将
selectdistinct项目
与此相结合

最终输出类似于:

date, project a total, project b total, project c total,
2014-02-01,0.5, 0.3, 10,
2014-02-02,1.3, 20, 3,
2014-02-03,20, 10, 10
...
SELECT
    start::date,
    sum(duration / 60) as "time logged",
    project
FROM
    time_records
GROUP BY
    start::date, project
ORDER BY
    start::date, project;
我可以通过以下方式获得每个项目的每个日期的总数:

date, project a total, project b total, project c total,
2014-02-01,0.5, 0.3, 10,
2014-02-02,1.3, 20, 3,
2014-02-03,20, 10, 10
...
SELECT
    start::date,
    sum(duration / 60) as "time logged",
    project
FROM
    time_records
GROUP BY
    start::date, project
ORDER BY
    start::date, project;
但是每个项目都有多个日期。我需要它是一个单独的行与每个项目的总数日期


如果SQL不在查询后编写一些代码,这有意义/可能吗?

一个简单的方法是使用
案例执行“手动”透视

选择日期(“开始”),
总和(当“项目”=“项目A”然后持续时间/60否则0结束时的情况)“项目A”,
总和(当“项目”=“项目B”然后持续时间/60否则0结束时的情况)“项目B”,
总和(当“项目”=“项目C”然后持续时间/60其他0结束时的情况)“项目C”
从时间记录
按日期分组(“开始”);

您应该可以使用来执行类似的操作,但我没有访问PostgreSQL的权限来加载模块并使用以下命令测试查询:-/

对于“透视”表或交叉制表,请使用

表定义 给定这个没有as标识符的经过消毒的表定义(这是一个很大的禁忌,即使您可以使用双引号强制它):

查询 请注意,我如何使用带有两个参数的变量来正确处理结果中缺少的项

SELECT *
FROM  crosstab (
   $$
   SELECT t_start::date
         , project
         , round(sum(duration / 60)::numeric, 2) AS time_logged
   FROM    time_records
   GROUP   BY 1,2
   ORDER   BY 1,2
   $$
  ,$$VALUES ('Project A'), ('Project B'),('Project C')$$
  ) AS t (
      t_start   date
    , project_a text
    , project_b text
    , project_c text
  );
结果:

t_start    | project_a | project_b | project_c
-----------|-----------|-----------|----------
2014-02-01 | 0.44      |           |
2014-02-02 | 0.69      | 2.43      |
2014-02-03 | 2.18      |           | 3.13
以Postgres 9.3进行测试

此相关答案中的解释、详细信息和链接:

查看“tablefunc”模块中的“crosstab”功能。这看起来很完美,感谢您对保留字的更新。鉴于此,是否可以从表本身生成
project_a
etc,可能是从子查询生成的?@JoshK:您需要两个步骤:1。基于表中的数据构建类似于上述的语句。2.执行该语句。SQL要求知道返回类型,因此这不是一步就能做到的。我写了很多。