用PostgreSQL连接查询计算百分比

时间:2018-10-08 05:38:50

标签: percentage postgresql-9.3

我试图通过加入3个表数据来计算百分比,以获取每个用户的tweet的positive_count,negative_count,neutral_count的百分比。我已经成功地获得了正数,负数和中性数,但是没有获得与百分比相同的数字,而不是分数。这是获取计数的查询:

SELECT 
   t1.u_id,count() as total_tweets_count , 
   (
     SELECT count() from t1,t2,t3 c 
      WHERE 
            t1.u_id='18839785' AND 
            t1.u_id=t2.u_id AND 
            t2.ts_id=t3.ts_id AND 
            t3.sentiment='Positive'
   ) as pos_count , 
   (
    SELECT count() from t1,t2,t3
     WHERE
           t1.u_id='18839785' AND 
           t1.u_id=t2.u_id AND 
           t2.ts_id=t3.ts_id AND
           t3.sentiment='Negative'
   ) as neg_count , 
   (
    SELECT count() from t1,t2,t3
     WHERE
           t1.u_id='18839785' AND
           t1.u_id=t2.u_id AND
           t2.ts_id=t3.ts_id AND
           t3.sentiment='Neutral'
   ) as neu_count
 FROM t1,t2,t3 
WHERE
      t1.u_id='18839785' AND
      t1.u_id=t2.u_id AND
      t2.ts_id=t3.ts_id

GROUP BY t1.u_id;

**OUTPUT:**  

u_id | total_tweets_count | pos_count | neg_count | neu_count 
-----------------+--------------------+-----------+-----------+------- 
18839785|         88 |        38 |        25 |        25
(1 row)

现在,我希望百分比相同而不是计数。我以以下方式编写了查询,但是失败了。

SELECT 
       total_tweets_count,pos_count,
       round((pos_count * 100.0) / total_tweets_count, 2) AS pos_per,neg_count,
       round((neg_count * 100.0) / total_tweets_count, 2) AS neg_per,
       neu_count, round((neu_count * 100.0) / total_tweets_count, 2) AS neu_per 
 FROM (
       SELECT
             count(*) as total_tweets_count,
             count(
                   a.u_id='18839785' AND
                   a.u_id=b.u_id AND
                   b.ts_id=c.ts_id AND
                   c.sentiment='Positive'
                  ) AS pos_count,
             count(
                   a.u_id='18839785' AND
                   a.u_id=b.u_id AND
                   b.ts_id=c.ts_id AND 
                   c.sentiment='Negative'
                  ) AS neg_count,
             count(
                   a.u_id='18839785' AND
                   a.u_id=b.u_id AND
                   b.ts_id=c.ts_id AND
                   c.sentiment='Neutral') AS neu_count
         FROM t1,t2, t3
        WHERE 
              a.u_id='18839785' AND 
              a.u_id=b.u_id AND
              b.ts_id=c.ts_id 
     GROUP BY a.u_id
    ) sub;

有人可以帮我实现以下每个用户数据的百分比吗?

u_id | total_tweets_count | pos_count | neg_count | neu_count 
------------------+--------------------+-----------+-----------+-----
18839785|      88 |        43.18 |        28.4 |        28.4
(1 row)

1 个答案:

答案 0 :(得分:1)

我不确定您要寻找什么。

对于初学者而言,您可以使用条件聚合而不是三个标量子查询(顺便说一句,无需在a.u_id上重复where条件)来简化查询。

您声明要“为所有用户计数”,因此您需要在主查询中删除WHERE子句。简化还消除了重复的WHERE条件。

select u_id, 
       total_tweets_count, 
       pos_count,
       round((pos_count * 100.0) / total_tweets_count, 2) AS pos_per,
       neg_count,
       round((neg_count * 100.0) / total_tweets_count, 2) AS neg_per,
       neu_cont,
       round((neu_count * 100.0) / total_tweets_count, 2) AS neu_per
from (
  SELECT 
     t1.u_id,
     count(*) as total_tweets_count, 
     count(case when t3.sentiment='Positive' then 1 end) as pos_count, 
     count(case when t3.sentiment='Negative' then 1 end) as neg_count, 
     count(case when t3.sentiment='Neutral' then 1 end) as neu_count 
  FROM t1
    JOIN t2 ON t1.u_id=t2.u_id 
    JOIN t3 t2.ts_id=t3.ts_id
  -- no WHERE condition on the u_id here
  GROUP BY t1.u_id
) t

请注意,我用“现代”显式JOIN运算符替换了WHERE子句中过时的,古老的和易碎的隐式连接

使用最新的Postgres版本,表达式count(case when t3.sentiment='Positive' then 1 end) as pos_count也可以重写为:

count(*) filter (where t3.sentiment='Positive') as pos_count

这更具可读性(我认为是可以理解的)。


在您的查询中,您可以通过使用相关的子查询,例如在u_id上实现全局WHERE条件的重复:

(
  SELECT count(*) 
  FROM t1 inner_t1 --<< use different aliases than in the outer query
    JOIN t2 inner_t2 ON inner_t2.u_id = inner_t1.u_id
    JOIN t3 inner_t3 ON inner_t3.ts_id = inner_t2.ts_id
  -- referencing the outer t1 removes the need to repeat the hardcoded ID
  WHERE innter_t1.u_id = t1.u_id 
) as pos_count

也不需要重复表t1,因此上面的内容可以重写为:

(
  SELECT count(*) 
  FROM t2 inner_t2 
    JOIN t3 inner_t3 ON inner_t3.ts_id = inner_t2.ts_id
  WHERE inner_t2.u_id = t1.u_id --<< this references the outer t1 table
) as pos_count

但是具有条件聚合的版本比使用三个标量子查询(即使您删除了t1表的不必要重复)仍然要快很多