如何过滤分析/窗口查询的结果?

时间:2009-08-26 14:19:46

标签: sql sql-server

我正在尝试找到重复的“密钥”,这样它们就可以被寻址并制作成正确的唯一密钥。

我最近了解到HAVING子句可以通过定位GROUP BY的结果来过滤聚合查询的结果。你按照所谓的“密钥”进行分组并且计算的地点是> 1,还有你的问题行。

我的问题是,窗口函数的等价物是什么?

下表对于名称和月份只应该是原子的,但是它使用的是日期详细的日期字段(例如,某些事情可能会在一个月内出现两次或更多次,而应该只是每月一次)。 / p>

select
  event_id,
  overly_specific_date,
  count(*) over(partition by event_id, substring(convert(char(8), overly_specific_date), 0, 7))
from events_historic
order by over(partition by event_id, substring(convert(char(8), overly_specific_date), 0, 7))

VS

select
  event_id,
  count(*)
from events_historic
group by event_id, substring(convert(char(8), overly_specific_date), 0, 7)
having count(*) > 1

第一个查询很好,因为它显示了我想要的内容,但我想将其过滤掉。我知道我可以在更大的查询或CTE中做到这一点,但我正在寻找像HAVING这样简洁的东西。第二个查询使用HAVING,但它不再显示键的一部分,overly_specific_date。

如何过滤第二个查询?

3 个答案:

答案 0 :(得分:0)

CTE版本:

WITH events AS (
      SELECT t.event_id,
             COUNT(*) 'num'
        FROM EVENTS_HISTORIC t
    GROUP BY e.event_id, YEAR(t.date), MONTH(t.date), DAY(t.date)
      HAVING COUNT(*) > 1)
SELECT eh.event_id,
       eh.date,
       e.num  
  FROM EVENTS_HISTORIC eh
  JOIN events e ON e.event_id = eh.event_id

非CTE版本:

SELECT eh.event_id,
       eh.date,
       e.num  
  FROM EVENTS_HISTORIC eh
  JOIN (SELECT t.event_id,
               COUNT(*) 'num'
          FROM EVENTS_HISTORIC t
      GROUP BY e.event_id, YEAR(t.date), MONTH(t.date), DAY(t.date)
        HAVING COUNT(*) > 1) e ON e.event_id = eh.event_id

答案 1 :(得分:0)

你的问题是overly_specific_date在一个组中有所不同(你按日期版本的日期聚合),因此无法显示overly_specific_date,因为该组不存在单个值。要列出所有违规日期,您必须实现rexem提出的某种子查询,以将该组链接到不同的日期。

然而,一个可能符合您目的的廉价黑客是在原始查询中选择overly_specific_date的MIN / MAX,以显示正在出现的违规日期范围。 (如果你想要的话,你也可以将月份版本转储到MIN语句中。)

答案 2 :(得分:0)

我推荐一个CTE,但是既然你问过,使用TOP(1)WITH TIES有一种偷偷摸摸的方法:

select top (1) with ties
  event_id,
  overly_specific_date,
  count(*) over (
    partition by event_id,
    substring(convert(char(8), overly_specific_date), 0, 7)
  ) as ct
from events_historic
order by 
  case when count(*) over (
    partition by event_id,
    substring(convert(char(8), overly_specific_date), 0, 7)
  ) > 1 then 0 else 1 end;

这并没有概括到许多其他有用的情况,但我认为在你的情况下它会起作用。