sql - 连接 PostgreSQL 表时,WHERE 中不允许使用聚合函数

标签 sql postgresql join postgresql-9.3 nullif

在使用 PostgreSQL 9.3.10 的游戏中,一些玩家已付费获得“VIP 状态”,这由包含 future 日期的 vip 列表示:

# \d pref_users

   Column   |            Type             |     Modifiers      
------------+-----------------------------+--------------------
 id         | character varying(32)       | not null
 first_name | character varying(64)       | not null
 last_name  | character varying(64)       | 
 vip        | timestamp without time zone | 

玩家还可以通过将nice列设置为truefalse或将其保留为null来评价其他玩家:

 # \d pref_rep

  Column   |            Type             |                         Modifiers                         
-----------+-----------------------------+-----------------------------------------------------------
 id        | character varying(32)       | not null
 author    | character varying(32)       | not null
 nice      | boolean                     | 

我通过发出以下 SQL JOIN 语句来计算 VIP 玩家的“声誉”:

# select u.id, u.first_name, u.last_name, 
  count(nullif(r.nice, false))-count(nullif(r.nice, true)) as rep 
  from pref_users u, pref_rep r 
  where u.vip>now()and u.id=r.id group by u.id order by rep asc;


           id            |           first_name           | last_name | rep  
-------------------------+--------------------------------+--------------------
 OK413274501330          | ali                            | salimov   | -193
 OK357353924092          | viktor                         | litovka   | -137
 DE20287                 | sergej warapow                 |              

我的问题如下:

如何查找所有对其他玩家进行过负面评价的玩家?

(背景是我添加了对其他人进行评价的可能性 - 所有 VIP 玩家。在此之前,只有获得积极评价的玩家才能对其他人进行评价)。

我尝试了以下方法,但出现以下错误:

# select count(*) from pref_rep r, pref_users u 
where r.author = u.id and u.vip > now() and 
u.id in (select id from pref_rep 
where (count(nullif(nice, false)) -count(nullif(nice, true))) < 0);

ERROR:  aggregate functions are not allowed in WHERE
LINE 1: ...now() and u.id in (select id from pref_rep where (count(null...
                                                             ^

更新:

我现在正在尝试使用临时表 -

首先,我用所有负面评价的 VIP 用户填充它,效果很好:

# create temp table my_temp as select u.id, u.first_name, u.last_name,
  count(nullif(r.nice, false))-count(nullif(r.nice, true)) as rep 
  from pref_users u, pref_rep r 
  where u.vip>now() and u.id=r.id group by u.id;

 SELECT 362

但是我的 SQL JOIN 返回了太多相同的行,我找不到那里缺少什么条件:

 # select u.id, u.first_name, u.last_name 
   from pref_rep r, pref_users u, my_temp t 
   where r.author=u.id and u.vip>now() 
   and u.id=t.id and t.rep<0;

           id            |           first_name           |         last_name          
-------------------------+--------------------------------+----------------------------
 OK400153108439          | Vladimir                       | Pelix
 OK123283032465          | Edik                           | Lehtik
 OK123283032465          | Edik                           | Lehtik
 OK123283032465          | Edik                           | Lehtik
 OK123283032465          | Edik                           | Lehtik
 OK123283032465          | Edik                           | Lehtik
 OK123283032465          | Edik                           | Lehtik

我在声明中遇到同样的问题(具有相同数据的多行):

# select u.id, u.first_name, u.last_name 
  from pref_rep r, pref_users u 
  where r.author = u.id and u.vip>now() 
  and u.id in (select id from my_temp where rep < 0);

我想知道这里可能缺少什么条件?

最佳答案

首先,我将编写您的第一个查询,如下所示:

select
  u.id, u.first_name, u.last_name,
  sum(case
        when r.nice=true then 1
        when r.nice=false then -1
      end) as rep 
from
  pref_users u inner join pref_rep r on u.id=r.id 
where
  u.vip>now()
group by
  u.id, u.first_name, u.last_name;

(和你的一样,但我觉得更清楚)。

要查找负面评价的玩家,您可以使用与以前相同的查询,只需添加 HAVING 子句:

having
  sum(case
        when r.nice=true then 1
        when r.nice=false then -1
      end)<0

要查找对玩家进行过评级的负面评级玩家,一种解决方案是:

select
  s.id, s.first_name, s.last_name, s.rep
from (
  select
    u.id, u.first_name, u.last_name,
    sum(case
          when r.nice=true then 1
          when r.nice=false then -1
        end) as rep 
  from
    pref_users u inner join pref_rep r on u.id=r.id 
  where
    u.vip>now()
  group by
    u.id, u.first_name, u.last_name
  having
    sum(case
          when r.nice=true then 1
          when r.nice=false then -1
        end)<0
  ) s
where
  exists (select * from pref_rep p where p.author = s.id)

最终可以从内部查询中删除having子句,并且您可以在外部查询上使用这个where子句:

where
  rep<0
  and exists (select * from pref_rep p where p.author = s.id)

关于sql - 连接 PostgreSQL 表时,WHERE 中不允许使用聚合函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34340543/

相关文章:

sql - 在 SQL (PSQL) 中,如何按行的分区进行分组(如何嵌套分组)?

mysql - MySQL 中何时使用单引号、双引号和反引号

sql - 使用一个插入命令插入多行

ruby-on-rails - 在 Ubuntu 9.1 Rails 开发箱中配置 Postgres 以进行 Cucumber 测试

windows - Postgresql 拒绝连接到服务器

php - 使用 LEFT JOIN 通过 Form 插入 MySQL

sql - Zend 如何创建左连接

Mysql分组计数日期范围内的数据行

mysql - SQL:选择其他表中不存在的位置

python - "Correct"在python网站中存储postgres密码的方法