是否可以通过分区没有子查询来限制窗口函数的结果?这段代码在postgres / mysql中。我正在寻找mysql和postgres中的解决方案。
例如:假设联接与问题无关紧要。
select acct.name, we.channel, count(*) as cnt,
max(count(*)) over (partition by name order by count(*) desc) as max_cnt
from web_events we join accounts acct
on we.account_id=acct.id
group by acct.name, we.channel
order by name, max_cnt desc;
此查询的结果为:
我只想显示每个窗口分区的第一行。 例如:带有cnt的行:[3M,19],[Abbott Labortories,20]
我尝试了以下不起作用的方法(向窗口函数添加了限制1):
select acct.name, we.channel, count(*) as cnt,
max(count(*)) over (partition by name order by count(*) desc limit 1) as max_cnt
from web_events we join accounts acct
on we.account_id=acct.id
group by acct.name, we.channel
order by name, max_cnt desc;
答案 0 :(得分:1)
我只想显示每个窗口分区的第一行。例如:带有cnt的行:[3M,19],[Abbott Labortories,20]
这里实际上不需要窗口函数,因为第一行的max_cnt
将始终等于cnt
。而是将DISTINCT ON
与GROUP BY
结合使用。
SELECT DISTINCT ON(expression [,...])仅保留给定表达式求值相等的每组行的第一行。使用与ORDER BY相同的规则来解释DISTINCT ON表达式(请参见上文)。请注意,除非使用ORDER BY来确保所需的行首先出现,否则每个组的“第一行”都是不可预测的
SELECT DISTINCT ON(acct.name)
acct.name
, we.channel
, COUNT(*) cnt
FROM web_events we
JOIN accounts acct
ON we.account_id=acct.id
GROUP BY 1, 2
ORDER BY name, cnt DESC;
这是sqlfiddle中的一个快速演示。 http://sqlfiddle.com/#!17/57694/8
当我第一次开始使用DISTINCT ON
时,我总是很困惑的一种方法是确保ORDER BY
子句中表达式的顺序以DISTINCT ON
中的表达式开始。在上面的示例中,ORDER BY
以acct.name
如果第一个位置并列,则将返回符合条件的第一行。这是不确定的。可以在ORDER BY
中指定其他表达式,以影响此设置中返回的行。
示例:
ORDER BY name, cnt DESC, channel = 'direct'
将返回包含facebook
的行,如果对于给定帐户,facebook
和direct
都产生相同的cnt
。
但是,请注意,使用这种方法,不可能返回所有与第一个位置并列的行,即,两行都包含facebook
和direct
(不使用子查询)。 / p>
DISTINCT ON
可以在同一语句中与GROUP BY
(上面的示例)和WINDOW FUNCTIONS
(下面的示例)组合。在逻辑上,DISTINCT ON
子句在LIMIT
之前进行评估。
例如,以下查询(但毫无意义)展示了DISTINCT ON
与WINDOW FUNCTION
的组合。它将为每个max_cnt
SELECT DISTINCT ON(mxcnt)
acct.name
, we.channel
, COUNT(*) cnt
, MAX(COUNT(*)) OVER (PARTITION BY acct.name) mxcnt
FROM web_events we
JOIN accounts acct
ON we.account_id=acct.id
GROUP BY 1, 2
ORDER BY mxcnt, cnt DESC;
答案 1 :(得分:0)
使用子查询。如果只需要一行(即使有平局),则使用row_number()
:
select name, channel, cnt
from (select acct.name, we.channel, count(*) as cnt,
row_number() over (partition by acct.name order by count(*) desc) as seqnum
from web_events we join
accounts acct
on we.account_id = acct.id
group by acct.name, we.channel
) wea
order by name;
如果有关系,如果一个帐户需要多行,则可以使用rank()
。