PostgreSQL:试图找到最高评级的上个月的小姐和先生

时间:2011-07-07 13:35:27

标签: sql postgresql join

my Drupal website用户可以互相评价,这些带时间戳的评分存储在 pref_rep 表中:

# select id, nice, last_rated from pref_rep where nice=true
  order by last_rated desc limit 7;
           id           | nice |         last_rated
------------------------+------+----------------------------
 OK152565298368         | t    | 2011-07-07 14:26:38.325716
 OK452217781481         | t    | 2011-07-07 14:26:10.831353
 OK524802920494         | t    | 2011-07-07 14:25:28.961652
 OK348972427664         | t    | 2011-07-07 14:25:17.214928
 DE11873                | t    | 2011-07-07 14:25:05.303104
 OK335285460379         | t    | 2011-07-07 14:24:39.062652
 OK353639875983         | t    | 2011-07-07 14:23:33.811986

另外,我将每个用户的性别保留在 pref_users 表中:

# select id, female from pref_users limit 7;
       id       | female
----------------+--------
 OK351636836012 | f
 OK366097485338 | f
 OK251293359874 | t
 OK7848446207   | f
 OK335478250992 | t
 OK355400714550 | f
 OK146955222542 | t

我正在尝试创建2个显示“上个月错过”和“上个月的先生”的Drupal块,但我的问题不是关于Drupal,所以请不要将它移到drupal.stackexchange.com; - )< / p>

我的问题是关于SQL:我怎么能找到最好的用户数 - 以及上个月的用户?我会有两个问题 - 一个是女性,另一个是非女性。

使用PostgreSQL 8.4.8 / CentOS 5.6和SQL有时候很难: - )

谢谢! 亚历

更新

我有一个很好的建议是将时间戳转换为字符串,以便查找上个月的记录(不是过去30天)

UPDATE2:

我最终做了字符串比较:

select r.id,
        count(r.id),
        u.first_name,
        u.avatar,
        u.city
from pref_rep r, pref_users u where
        r.nice=true and
        to_char(current_timestamp - interval '1 month', 'IYYY-MM') =
        to_char(r.last_rated, 'IYYY-MM') and
        u.female=true and
        r.id=u.id
group by r.id , u.first_name, u.avatar, u.city
order by count(r.id) desc
limit 1

1 个答案:

答案 0 :(得分:0)

假设您在每月的第一天运行一次,并缓存结果,因为在每个页面上计算投票都是没用的。

首先是一些日期算术:

SELECT now(), 
       date_trunc( 'month', now() ) - '1 MONTH'::INTERVAL, 
       date_trunc( 'month', now() );

              now              |        ?column?        |       date_trunc       
-------------------------------+------------------------+------------------------
 2011-07-07 16:24:38.765559+02 | 2011-06-01 00:00:00+02 | 2011-07-01 00:00:00+02

好的,我们获得了“上个月”日期时间范围的界限。 现在我们需要一些窗口函数来获得每个性别的第一行:

SELECT * FROM (
   SELECT *, rank( ) over (partition by gender order by score desc ) 
   FROM (
      SELECT user_id, count(*) AS score FROM pref_rep 
      WHERE nice=true 
      AND last_rated >= date_trunc( 'month', now() ) - '1 MONTH'::INTERVAL
      AND last_rated <  date_trunc( 'month', now() )
      GROUP BY user_id) s1 
   JOIN users USING (user_id)) s2 
WHERE rank=1;

请注意,如果出现这种情况,可以为您提供多行。

编辑:

  

我有一个很好的建议,即将时间戳转换为字符串   查找上个月的记录(不是过去30天)

date_trunc()效果更好。

如果您进行2次查询,则必须两次进行count()。由于用户可能会为其他用户多次投票,因此该表可能会更大,因此扫描一次是件好事。

你不能“将加入回到用户桌面上的查询的外部”,因为你需要性别......

上面的查询大约需要30毫秒,1k用户和10万票,所以你肯定想要缓存它。