使用前10个查询然后搜索与其关联的所有记录

时间:2015-03-17 23:08:20

标签: sql postgresql greatest-n-per-group sql-limit

我对sql一般都没有超级经验,而且我正在尝试完成一项非常具体的任务 - 我想首先运行一个查询来获取所有单位的ID,并获得最高的点击数,然后从该运行再次获取在特定时间段内这些ID的所有类型的命中的消息和计数。对于第一个查询,我有这个:

SELECT entity, count(entity) as Count
from plugin_status_alerts
where entered BETWEEN now() - INTERVAL '14 days' AND now()
group by entity
order by count(entity) DESC
limit 10

导致此回报:

"38792";3
"39416";2
"37796";2
"39145";2
"37713";2
"37360";2
"37724";2
"39152";2
"39937";2
"39667";2

然后使用该结果集然后运行另一个按实体和status_code排序的查询。我试过这样的事情:

SELECT status_code, entity, COUNT(status_code) statusCount
FROM plugin_status_alerts
where updated BETWEEN now() - INTERVAL '14 days' AND now() AND entity IN 
(SELECT id.entity, count(id.entity) as Count
from plugin_status_alerts id
where id.updated BETWEEN now() - INTERVAL '14 days' AND now()
group by id.entity
order by count(id.entity) DESC
limit 10
)
GROUP BY status_code, entity

但我收到了错误

ERROR: subquery has too many columns

我不确定这是否是我应该去的路线,或者我是否应该尝试自我加入 - 不管怎样纠正现在发生的事情。

2 个答案:

答案 0 :(得分:1)

使用JOIN代替IN (subquery)。这通常更快,如果需要,您可以使用子查询中的其他值(例如每entity的总计数):

SELECT entity, status_code, count(*) AS status_ct
FROM  (
   SELECT entity  -- not adding count since you don't use it, but you could
   FROM   plugin_status_alerts
   WHERE  entered BETWEEN now() - interval '14 days' AND now()
   GROUP  BY entitiy
   ORDER  BY count(*) DESC, entitiy  -- as tie breaker to get stable result
   LIMIT  10
   ) sub
JOIN   plugin_status_alerts USING (entity)
WHERE  updated BETWEEN now() - interval '14 days' AND now()
GROUP  BY 1, 2;

注释

  • 如果您没有按设计进行日后记录,则可以简化:

    WHERE  entered > now() - interval '14 days'
    
  • 由于子查询只返回与entity子句合并的单个列(USING),因此列名称是明确的,我们不需要表格限定。

  • 按计数排序后,
  • LIMIT 10可能不明确。多行可以绑定第10行。如果没有ORDER BY中的其他项目,Postgres将返回任意选择,这可能会也可能不会。但是查询的结果可以在调用之间进行更改,而不会对基础数据进行任何更改。通常情况下,这是不可取的,您应该在列表中添加列或表达式以打破关系

  • count(*)count(status_code)快一点并且做同样的事情 - 除非status_code可以为null,在这种情况下,您将获得0作为计数此行(count()永远不会返回null)而不是实际的行计数,这是无用的或主动错误的。在此处使用count(*)

  • GROUP BY 1, 2只是语法简写。详细说明:

答案 1 :(得分:0)

当您将第一个查询插入第二个查询并在in子句中使用时,当in只需要一个时,您仍会返回两列。要么这样做:

SELECT status_code, entity, COUNT(status_code) statusCount
FROM plugin_status_alerts
where updated BETWEEN now() - INTERVAL '14 days' AND now() 
AND entity IN (
    SELECT id.entity
    from plugin_status_alerts id
    where id.updated BETWEEN now() - INTERVAL '14 days' AND now()
    group by id.entity
    order by count(id.entity) DESC
    limit 10
)
GROUP BY status_code, entity

或者将第一个查询用作派生表并与之连接。