Оконные функции и оптимизатор запросов
У меня есть таблица со следующей структурой.
|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
s? Будет ли мой фильтр диапазона дат применен во внутреннем выборе до суммы?
1 ответ
Создав этот вопрос, я понял, что это должно быть достаточно просто, чтобы проверить его.
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 год?