11

假设我有一个包含 3 个字段的简单表:“地点”、“用户”和“字节”。假设,在某个过滤器下,我想按“地点”分组,并且对于每个“地点”,汇总该地点的所有字节,并随机选择该地点的用户(从所有符合条件的用户中统一选择'where' 过滤器和相关的 'place')。如果有一个“随机选择”聚合函数,我会这样做:

SELECT place, SUM(bytes), SELECT_AT_RANDOM(user) WHERE .... GROUP BY place;

...但我找不到这样的聚合函数。我错过了什么吗?什么是实现这一目标的好方法?

4

4 回答 4

5

如果您的 RDBMS 支持分析功能。

WITH T
     AS (SELECT place,
                Sum(bytes) OVER (PARTITION BY place) AS Sum_bytes,
                user,
                Row_number() OVER (PARTITION BY place ORDER BY random_function()) AS RN
         FROM   YourTable
         WHERE  .... )
SELECT place,
       Sum_bytes,
       user
FROM   T
WHERE  RN = 1; 

对于 SQL ServerCrypt_gen_random(4)NEWID()将是可以替代的示例random_function()

于 2012-11-18T14:34:58.583 回答
3

我认为您的问题是特定于 DBMS 的。如果您的 DBMS 是 MySql,您可以使用这样的解决方案:

SELECT place_rand.place, SUM(place_rand.bytes), place_rand.user as random_user
FROM
  (SELECT place, bytes, user
   FROM place
   WHERE ...
   ORDER BY rand()) place_rand
GROUP BY
  place_rand.place;

子查询以随机顺序排列记录。外部查询按place、求和bytes并返回第一个随机用户,因为用户不在聚合函数中,也不在 group by 子句中。

于 2012-11-18T15:27:06.917 回答
1

使用自定义聚合函数,您可以编写如下简单的表达式:

SELECT place, SUM(bytes), SELECT_AT_RANDOM(user) WHERE .... GROUP BY place;

SELECT_AT_RAMDOM将是自定义聚合函数。

这正是PostgreSQL的一个实现

于 2017-10-14T22:22:54.427 回答
0

我会对 Martin 的解决方案做一些改动:

select place, sum(bytes), max(case when seqnum = 1 then user end) as random_user
from (select place, bytes,
             row_number() over (partition by place order by newid()) as sequm
       from t
      ) t
group by place

(其中 newid() 只是获取随机数的一种方法,具体取决于数据库。)

出于某种原因,我更喜欢这种方法,因为它在外部查询中仍然具有聚合功能。如果您正在总结一堆领域,那么这对我来说似乎更清晰。

于 2012-11-18T23:24:48.643 回答