分组并计算每个不同值的百分比

时间:2018-02-04 10:39:17

标签: sql postgresql

Postgresql 9.6有两个表:

      id  | name  |
   -------+-------+
      1   | Mars  |
      2   | Pluto |
      3   | Moon  |
      4   | Venus |


     id | p_id | action |
   -------+-------+-----+
     1  |  1   | LANDED |
     2  |  1   | UNSEEN |
     3  |  1   | SEEN   |
     4  |  1   | SEEN   |
     5  |  2   | LANDED |
     6  |  3   | SEEN   |
     7  |  3   | SEEN   |
     8  |  3   | UNSEEN |
     9  |  3   | LANDED |
    10  |  3   | LANDED |
    11  |  3   | LANDED |

我无法找出一个查询来获取显示每个操作百分比的表格,
比如那样:

      p_id | name  | SEEN | UNSEEN | LANDED |
   --------+-------+------+--------+--------+
       1   | Mars  |  10% |   30%  |   60%  |
       2   | Pluto |   0% |    0%  |  100%  |
       3   | Moon  |  25% |   35%  |   30%  |
       4   | Venus |   0% |    0%  |    0%  |

任何帮助都将不胜感激 谢谢,
佩雷斯

3 个答案:

答案 0 :(得分:1)

您可以使用带有过滤器的<script> // create youtube player var player; //$array = just an array of strings //$array_position = position in array <?php $array_position = 0; ?> function onYouTubePlayerAPIReady() { player = new YT.Player('player', { width: '640', height: '390', videoId: '<?php echo $array[$array_position];?>', events: { onStateChange: onPlayerStateChange } }); } // when video ends the $array_poisition should increment everytime function onPlayerStateChange(event) { if(event.data === 0) { <?php $array_position++; ?> //change the id of the video player.loadVideoById('<?php echo $array[$array_position];?>'); } } </script> 来计算每个类别的实例数:

count(*)
由于左连接,select n.id, name, count(*) filter (where action = 'SEEN') as seen, count(*) filter (where action = 'UNSEEN') as unseen, count(*) filter (where action = 'LANDED') as landed, count(*)::dec as total from names n left join actions a on a.p_id = n.id group by n.id order by n.id; id | name | seen | unseen | landed | total ----+-------+------+--------+--------+------- 1 | Mars | 2 | 1 | 1 | 4 2 | Pluto | 0 | 0 | 1 | 1 3 | Moon | 2 | 1 | 3 | 6 4 | Venus | 0 | 0 | 0 | 1 (4 rows) 的{​​p> Total不正确(1)。事实上,我们可以避免在下一步中将0除以。

在派生表(或CTE)中使用上述查询来计算百分比:

Venus

答案 1 :(得分:1)

我会使用avg()执行此操作:

select n.id, n.name, 
       avg( (action = 'SEEN')::int ) as seen,
       avg( (action = 'UNSEEN')::int ) as unseen,
       avg( (action = 'LANDED')::int ) as landed
from names n left join
     actions a
     on a.p_id = n.id
group by n.id, n.name;

这会将值生成为比率。将它们格式化为%的字符串似乎更适合应用程序层。

答案 2 :(得分:1)

您可以使用窗口函数计算百分比,并使用crosstab将行移动到列。请检查this one

create table body(id int, name varchar(256));

insert into body(id, name) values ( 1, 'Mars' ), ( 2, 'Pluto' ), (3, 'Moon' ), ( 4, 'Venus');

create table actions(id int, p_id int, action varchar(256));

insert into actions (id, p_id, action) values
( 1, 1, 'LANDED'),
( 2, 1, 'UNSEEN'),
( 3, 1, 'SEEN'),
( 4, 1, 'SEEN'),
( 5, 2, 'LANDED'),
( 6, 3, 'SEEN'),
( 7, 3, 'SEEN'),
( 8, 3, 'UNSEEN'),
( 9, 3, 'LANDED'),
(10, 3, 'LANDED'),
(11, 3, 'LANDED');


SELECT *
FROM crosstab($$
    select p_id as id, action, ((times / sum(times) over (partition by p_id)) * 100)::float as percentage
    from (
        select action, p_id, count(*) as times
        from actions 
        group by p_id, action
    )x   
    order by 1, 2
  $$
) as percentage ("id" int, "LANDED" float, "SEEN" float, "UNSEEN" float);