【问题标题】:Show multiple columns from a group of records显示一组记录中的多个列
【发布时间】:2014-10-24 16:53:59
【问题描述】:

给定表格:

score | name | time | nick
1       'A'    1      'X' 
4       'A'    2      'X'
10      'A'    3      'X'
10      'A'    4      'X'
1       'A'    5      'X'
1       'B'    6      'Z' 
4       'C'    7      'Z'

我想创建一个包含多列的输出,第一个是分数,其他的sum(时间)为name||'_time_'::text||nick

原来是这样:

score | A_time_X | B_time_Z
1       6          0
4       2          0
10      7          0
1       0          6  
4       0          7

每个分数的列显示 GROUP (score,name,nick) 相同时的时间总和。 nick 的其他值将显示更多列。

这可能吗?

【问题讨论】:

  • 请解释“多列,第一列是分数,其他列是总和(时间)作为名称||'time'::text||nick”跨度>
  • 得分第一列。然后每组(分数,名称,昵称)多一列,总和(时间)的值。列名将是:_'time'_。 name 和 nick 被每个不同的组合替换。如上例。
  • 结果的最后一行应该是4 0 0,而不是4 0 7,因为源表有name = 'C'

标签: sql postgresql multiple-columns aggregation crosstab


【解决方案1】:

group by 部分很简单。之后,您将旋转A_time_XB_time_Z。一种旋转方式是case 构造:

select  score
,       coalesce(case when name = 'A' and nick = 'X' then sum(time) end,0) as A_time_X
,       coalesce(case when name = 'B' and nick = 'Z' then sum(time) end,0) as B_time_Z
from    Table1
group by
        score
,       name
,       nick

Working example at SQL Fiddle.

有关更多旋转选项,请参阅this answer

【讨论】:

  • 行得通!有没有可能让它更有活力?像这样,对于每个新名称或时间,您都必须手动更新查询。所以就像假设 name 只能是 {'A','B'} 但 nick 可能会改变(新记录会出现!
  • SQL 中的动态透视很复杂。我在底部链接的答案有一些选择。
【解决方案2】:

穷人的支点与CASE

我会在一个子查询中聚合以简化。也可能更快:

SELECT score
     , CASE WHEN name = 'A' AND nick = 'X' THEN sum_time ELSE 0 END AS a_x
     , CASE WHEN name = 'B' AND nick = 'Z' THEN sum_time ELSE 0 END AS b_z
FROM  (
   SELECT score, name, nick, COALESCE(sum(time), 0) AS sum_time
   FROM   table1
   GROUP  BY 1,2,3
   ) sub
ORDER  BY score, name, nick;

crosstab()

首先在这里阅读基本说明:

由于crosstab() 期望 值有一个 列,因此从(name, nick) 的组合生成唯一键:

SELECT * FROM crosstab(
   $$
   SELECT score
        , CASE WHEN name = 'A' AND nick = 'X' THEN 1
               WHEN name = 'B' AND nick = 'Z' THEN 2 END AS key
        , COALESCE(sum(time), 0) AS val
   FROM   table1
   WHERE (name = 'A' AND nick = 'X' OR
          name = 'B' AND nick = 'Z')   -- exclude rest (optional, faster)
   GROUP  BY name, nick, score
   ORDER  BY key, score;  -- (!) reversed order to get your untypical result
   $$
  ,'VALUES (1),(2)'       -- match key values in order
  ) AS t (score int, a_x int, b_z int);

生成您的结果(最后一行中的错误除外)。
但是,通常您会希望:

   ORDER  BY score, key;  -- (!) typical case

要得到这个结果(一行中所有相同分数的值):

score | A_time_X | B_time_Z
1       6          6
4       2          7
10      7          NULL

SQL Fiddle 没有 crosstab() 因为目前无法在那里安装其他模块。

动态查询?

很难得到,as @Andomar already comemnted。看看这里有什么可能

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 2021-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多