窗口函数和查询优化器

时间:2019-02-27 17:18:56

标签: sql-server over-clause

我有一个具有以下结构的表。

|anId|     aDate|aNumber|
-------------------------
|   1|2018-01-20|    100|
|   1|2019-01-01|   -100|
|   1|2019-02-01|     10|
|   2|2019-01-02|     40|

我有一个查询要在特定日期返回每个aNumber的先前(含)总和是否为> 0

select
  anId,
  aDate,
  1 as aStatus
from (
  select
    anId,
    aDate,
    sum(aNumber) OVER (
      PARTITION BY anId
      ORDER BY aDate
      ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
    ) as aSum
  from
    myTable
)
where
  aSum > 0
;

因此该查询将返回

|anId|     aDate|aStatus|
-------------------------
|   1|2018-01-20|      1|
|   2|2019-01-02|      1|
|   1|2019-02-01|      1|

现在,我已将查询变成视图myView。我想在此视图中查询日期范围。我可以每天/每月/每年查询表,但是我希望能够从一个日期范围导出查询结果,然后导出/追加下一个日期范围的结果。

select
  anId,
  aDate,
  aStatus
from
  myView
where
  aDate between (2018-01-01) and (2018-12-31)
;

会回来

|anId|     aDate|aStatus|
-------------------------
|   1|2018-01-20|      1|

第二年

select
  anId,
  aDate,
  aStatus
from
  myView
where
  aDate between (2019-01-01) and (2019-12-31)
;

应该返回

|anId|     aDate|aStatus|
-------------------------
|   2|2019-01-02|      1|
|   1|2019-02-01|      1|

允许我将结果拼接在一起,以获得未经过滤的原始查看记录。


好吧,现在已经设置好阶段了,我对这种方法的担心是,当我从视图中过滤日期时,它将影响窗口化功能。

当我筛选2019年时,窗口总和是否仍将包括2018年的aNumber?我的日期范围过滤器会在总和之前应用于内部选择吗?

1 个答案:

答案 0 :(得分:0)

创建了这个问题之后,我意识到测试它应该足够简单。

CREATE TABLE [dbo].[jnix_temp](
    [anId] [char](36) NOT NULL,
    [aDate] [datetime2](7) NULL,
    [aNumber] [int] NULL
) ON [PRIMARY]
GO

insert into myTable(anId,aDate,aNumber) values ('1','2018-01-20',100);
insert into myTable(anId,aDate,aNumber) values ('1','2019-01-01',-100);
insert into myTable(anId,aDate,aNumber) values ('1','2019-02-01',10);
insert into myTable(anId,aDate,aNumber) values ('2','2019-01-20',40);

使用子选择而不是创建实际视图

select
    *
from (
    select
      anId,
      aDate,
      1 as aStatus
    from (
      select
        anId,
        aDate,
        sum(aNumber) OVER (
          PARTITION BY anId
          ORDER BY aDate
          ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
        ) as aSum
      from
        myTable
    ) a
    where
      a.aSum > 0
) b
where
    b.aDate < '2019-01-01'
;

返回:

|anId|     aDate|aStatus|
-------------------------
|   1|2018-01-20|      1|

select
    *
from (
    select
      anId,
      aDate,
      1 as aStatus
    from (
      select
        anId,
        aDate,
        sum(aNumber) OVER (
          PARTITION BY anId
          ORDER BY aDate
          ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING
        ) as aSum
      from
        myTable
    ) a
    where
      a.aSum > 0
) b
where
    b.aDate >= '2019-01-01'
;

返回:

|anId|     aDate|aStatus|
-------------------------
|   2|2019-01-02|      1|
|   1|2019-02-01|      1|

这确认日期过滤器不影响总和。但是,让我有些担心的是,子查询不是最理想的,因为它可能对总数超过所需数据的总和进行计算。即。当我想要2018年数据时,它仍在计算2019年数据的总和吗?