2012-11-18 121 views
8

说我有一个简单的表,有3个字段:'地点','用户'和'字节'。比方说,在某个过滤器下,我想按'地点'分组,并为每个“地点”合计该地点的所有字节,并随机选择该地点的用户(统一来自所有符合'where'过滤器和相关'地点')。如果有一个“随机选择”聚合函数,我会这样做:SQL随机聚合

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

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

+4

这是什么RDBMS? –

+0

我不知道任何具有这种功能的个人RDBMS。大多数需要使用一些其他机制来实现相同的结果*(例如为每个用户分配一个随机数,然后选择具有最高值的用户)。*但每个都有不同的功能,并且每个功能的表现都不相同。所以,这确实是一个RDBMS特定的问题。 – MatBailie

+0

如果您使用的是MySQL,只需编写一个不正确的“GROUP BY”(例如,不要在用户上应用聚合),它将随机选择一行。 –

回答

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 Server Crypt_gen_random(4)NEWID()会的东西,可以为random_function()

2

被取代的例子,我认为你的问题是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子句中。

0

我会做有点变化对马丁的解决方案:

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()仅仅是一个得到一个随机数,取决于数据库的方式。)

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

0

使用自定义聚合函数,你可以写表达式一样简单:

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

SELECT_AT_RAMDOM将是自定义的聚合函数。

这里正好是an implementationPostgreSQL