【发布时间】:2021-12-15 02:36:43
【问题描述】:
我有一个查询,它正在对项目进行分组,选择一个组中的项目数,以及该组在 where 子句中未过滤掉的所有项目中的百分比
我想删除所有包含两个或更少项目的组,以减少占整个数据集一小部分的结果。
这是我的(简化的)查询:
select count(i.itemId) as itemCount,
concat(format(100 * count(i.itemId) / sum(count(i.itemId)) over (), 2), '%') as totalPercentage
from thing t
join item i on t.thingId = i.thingId
where t.createdDate > startdate and t.createdDate < enddate
group by t.thingId
order by count(i.itemId) desc, t.thingId desc;
我认为我应该像这样添加一个有子句:
...
group by t.thingId
having count(i.itemId) > 2
order by count(i.itemId) desc, t.thingId desc;
会解决问题,但是当我这样做时,结果显示的总百分比现在不准确,因为 sum(count(i.itemId)) over () 现在忽略了其中包含 2 个或更少项目的组。
我知道可以通过将此查询设为内部查询,然后在此查询之外的选择中进行过滤来做到这一点,但我不希望这样做,因为在我的团队中,我们尽量避免使用内部查询除非必要,否则查询。
我也知道可以制作一个临时表,并通过从该临时表中进行选择来过滤它,但我什至不想进入那个,因为它看起来很丑。
TLDR:是否可以从选择结果中过滤掉组,但仍将它们包含在 sum() over () 子句中而没有任何恶作剧?
【问题讨论】:
-
任何过滤都会从结果集中删除行,因此计算无法访问它们。分析函数在查询执行的最后一步计算(在
select列表表达式评估和order by之前),因此要过滤掉一些行,您必须将计算放入子查询并在外部查询中应用过滤器 -
避免“内部查询”(子查询/内联视图)表明了对 SQL 的根本误解。您错误地将其视为命令式语言,但它是声明性的;语法允许你表达一个问题,然后 DBMS 生成一个计划来解决它。仅仅因为某些东西在子查询中并不意味着 DBMS 会盲目地执行它。谓词下推、类宏展开等方法,意味着生成的计划不是那么幼稚。例如
SELECT * FROM (SELECT * FROM X) AS Y WHERE foo='bar'产生与SELECT * FROM X WHERE foo='bar'完全相同的计划