Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 分组并计算每个不同值的百分比_Sql_Postgresql - Fatal编程技术网

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

Sql 分组并计算每个不同值的百分比,sql,postgresql,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 |

带两个表的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%  |
任何帮助都将不胜感激。
谢谢,

Peraz

您可以使用带有过滤器的
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)
维纳斯的
Total
不正确(1),因为左连接。事实上,这没关系,因为我们可以在下一步中避免除以0

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

select
    id, name,
    round(seen/ total* 100, 0) as seen,
    round(unseen/ total* 100, 0) as unseen,
    round(landed/ total* 100, 0) as landed
from (
    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
    ) s
order by id;

 id | name  | seen | unseen | landed 
----+-------+------+--------+--------
  1 | Mars  |   50 |     25 |     25
  2 | Pluto |    0 |      0 |    100
  3 | Moon  |   33 |     17 |     50
  4 | Venus |    0 |      0 |      0
(4 rows)    

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


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

您可以使用窗口函数计算百分比,并使用
交叉表将行移动到列。请核对:


SQL错误:错误:列“n.name”必须出现在GROUP BY子句中或在聚合函数中使用。added
groupby n.id,name
有效。通常
id
是主键,当不需要将其他列放在
groupby
子句中时,也请参见@klin:return what-which-which-which-which-which-which-which-which-which-which-which-which-which-which-which-whtable@Ivan布卢斯基:有趣的方法,但是在一个巨大的table@GordonLinoff对我来说是最简单易懂的方法,在一个大数据集上受苦感谢你们所有人的宝贵回复!
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;
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);