Количество строк за каждый день между двумя столбцами даты SQL Сервер - PullRequest
0 голосов
/ 21 января 2020

У меня есть таблица 'events':

id | name | date_start | date_end
---+------+------------+------------
1  | aaa  | 2020-01-01 | 2020-01-03
2  | bbb  | 2020-01-02 | 2020-01-05 

И я хочу посчитать строки для каждого дня между date_start и date_end из этой таблицы, например:

  • из первого ряда, я хочу, чтобы результат выглядел так:
date       | count
-----------+-------
2020-01-01 | 1
2020-01-02 | 1
2020-01-03 | 1
  • из второго ряда:
date       | count
---------------------
2020-01-02 | 1
2020-01-03 | 1
2020-01-04 | 1
2020-01-05 | 1

Итак, окончательный результат должно выглядеть так:

date       | count
-----------+-------
2020-01-01 | 1
2020-01-02 | 2
2020-01-03 | 2
2020-01-04 | 1
2020-01-05 | 1

Можно ли это сделать с sql или мне нужно рассчитать его на сервере? Эта таблица будет иметь тысячи строк, поэтому я не хочу загружать их все, когда мне нужен только этот результат.

Использование ASP. NET Core 3.1 с SQL Server.

Ответы [ 3 ]

1 голос
/ 21 января 2020

Вы можете использовать рекурсив cte:

with cte as (
   select t.date_start, t.date_end
   from table t
   union all
   select dateadd(day, 1, date_start), date_end
   from cte c
   where c.date_start < c.date_end
)
select date_start, count(*) as cnt
from cte c
group by date_start
option (maxrecursion 0)
0 голосов
/ 21 января 2020

Обычно это делается с календарем. См. Пример данных ниже и запрос:

declare @tbl table (id int, name varchar(20), date_start date, date_end date)
insert into @tbl values
( 1  , 'aaa'  , '2020-01-01' , '2020-01-03'),
( 2  , 'bbb'  , '2020-01-02' , '2020-01-05');
-- set boundaries for calendar
declare @startDate date, @endDate date;
select @startDate = min(date_start), @endDate = max(date_end) from @tbl;

;with calendar as (
    select @startDate dates
    union all
    select dateadd(day, 1, dates) from calendar
    where dates < @endDate
)
select c.dates, count(*) from calendar c
join @tbl t on c.dates between t.date_start and t.date_end
group by c.dates
0 голосов
/ 21 января 2020

Здесь удобно использовать рекурсивное CTE (если у вас нет таблицы чисел или таблицы календаря).

with cte as (
      select id, name, date_start, date_end
      from t
      union all
      select id, name, dateadd(day, 1, date_start), date_end
      from t
      where date_start < date_end
     )
select date_start as date, count(*)
from cte
group by date_start
order by date_start;

Если какой-либо из периодов длиннее 100 дней, вам нужно добавить option (maxrecursion) к запросу.

...