对查询应用于子查询行的谓词计数的SQL查询

时间:2014-06-29 23:24:48

标签: sql postgresql

我要执行一些有点复杂的SQL查询,而且我不确定正确的策略是什么。

考虑模型:

event
  foreignId Int
  time      UTCTime
  success   Bool

并假设我有一个谓词,我们可以调用trailingSuccess,如果最后True nevents,则为success。我想测试这个谓词。也就是说,我想在event上运行一个查询,该查询返回foreignId的计数,event每个success都是n event } {或更多}记录了SELECT count (*) FROM (SELECT e.foreignId FROM event e ... ORDER BY e.time ASC LIMIT n)

我正在使用Postgres,如果重要的话,但如果可能的话,我宁愿留在ANSI片段中。

计算此查询的合理策略是什么?

到目前为止,我的代码如下:

foreign_id    time     success
1             14:00    True
1             15:00    True
1             16:00    True
1             17:00    True
2             14:00    False
2             15:00    True
2             16:00    True
2             17:00    True
3             14:00    True
3             15:00    True
3             16:00    True

显然,我没有走得太远。我不确定如何表达一个量化多行的谓词。

对于假设用法,n = 4就可以了。

示例数据:

foreign_id

对于示例数据,查询应返回1,因为有n = 4个成功事件,其中foreign_id = 1. foreign_id 2不计算,因为在最后4个中有一个假值{{1因为没有足够的事件使用foreign_id = 3,所以3不计算。

4 个答案:

答案 0 :(得分:2)

尝试找到最新的"不成功"使用简单的foreignID子句输入每个GROUP BY的毛发。在子查询中使用它,您可以将它连接回表,计算匹配foreignID并且有更新时间的记录(对于每个foreignID)。

类似的东西:

SELECT lastn.foreignID, count(*)
FROM 
 (SELECT foreignID, MAX(time) AS lasttime
 FROM event
 WHERE success = 'n'
 GROUP BY foreignID
 ) AS lastn
JOIN event AS e
 ON e.foreignID = lastn.foreignID
 AND e.time > lastn.lasttime
GROUP BY lastn.foreignID;

您可以尝试使用左连接等来根据需要调整它。

答案 1 :(得分:1)

第一个派生表选择至少包含n个事件的所有foreignIds。子查询检查每个foreignId的最后n个事件是否都成功。

SELECT COUNT(*)
FROM (
    SELECT foreignId
    FROM event        
    GROUP BY foreignId
    HAVING COUNT(*) >= n
) t1
WHERE (
    SELECT COUNT(CASE WHEN NOT success THEN 1 END) = 0
    FROM event
    WHERE foreignId = t1.foreignId
    ORDER BY time DESC
    LIMIT n
)

答案 2 :(得分:1)

select count(*)
from (
    select
        foreignId,
        row_number() over(partition by foreignId order by "time" desc) as rn,
        success
    from event
) s
where rn <= n
group by foreignId
having bool_and(success)

答案 3 :(得分:0)

我最后在sqlfiddle上乱了一会儿,直到我到达这里:

select count (*)
  from (select count (last.foreignId) as cnt
          from (select foreignId
                  from event
                  and   success = True
                  order by time desc
                  ) as last
          group by last.foreignId) as correct
  where correct.cnt >= 4

我想我所添加的洞察力是每一层“选择”都可以被认为是内部选择的过滤器。