Оконные функции и оптимизатор запросов - PullRequest
0 голосов
/ 27 февраля 2019

У меня есть таблица со следующей структурой.

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

У меня есть запрос на конкретную дату, чтобы вернуть, является ли предыдущая (включительно) aNumber s сумма > 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 голосов
/ 27 февраля 2019

После создания этого вопроса я понял, что его достаточно просто протестировать.

CREATE TABLE [dbo].[myTable](
    [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 год?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...