Получить количество активных пользователей за каждый день - PullRequest
2 голосов
/ 10 июня 2019

У меня есть данные, которые дают представление о пользователе, когда пользователь подписался на услугу, в городе и когда он истекает.

Это как показано ниже

+------+------------+------------+
| City | Start_Date |  End_Date  |
+------+------------+------------+
| LA   | 2019-06-01 | 2019-06-03 |
| LA   | 2019-06-07 | 2019-06-10 |
| LA   | 2019-06-09 | 2019-06-11 |
| LA   | 2019-06-13 | 2019-06-14 |
| LO   | 2019-06-01 | 2019-06-05 |
| LO   | 2019-06-04 | 2019-06-05 |
| LO   | 2019-06-07 | 2019-06-09 |
| LO   | 2019-06-08 | 2019-06-09 |
+------+------------+------------+

Я хочу, чтобы количество активных пользователей для каждого города на каждый день в определенный день

Вывод должен быть несколько похож на

+------+------------+-------+
| City |    Day     | Count |
+------+------------+-------+
| LA   | 2019-06-01 |     1 |
| LA   | 2019-06-02 |     1 |
| LA   | 2019-06-03 |     1 |
| LA   | 2019-06-04 |     0 |
| LA   | 2019-06-05 |     0 |
| LA   | 2019-06-06 |     0 |
| LA   | 2019-06-07 |     1 |
| LA   | 2019-06-08 |     1 |
| LA   | 2019-06-09 |     2 |
| LA   | 2019-06-10 |     2 |
| LA   | 2019-06-11 |     1 |
| LA   | 2019-06-12 |     0 |
| LA   | 2019-06-13 |     1 |
| LA   | 2019-06-14 |     1 |
| LA   | 2019-06-15 |     0 |
+------+------------+-------+

Вывод, который я показал, предназначен только для City LA, и я также хочу получить аналогичные выходные данные для каждого города в таблице.

Описание моего вывода

  1. В City = LA на Day = 2019-06-01 был 1 пользователь с активной подпиской, аналогично для Day = 2019-06-02.
  2. В City = LA на Day = 2019-06-09 было 2 пользователя с активной подпиской и т. Д.

Любая помощь будет оценена

Ссылка SQL Fiddle

Ответы [ 6 ]

4 голосов
/ 10 июня 2019

Вам нужен диапазон дат.Цифры или таблица подсчета удобны.Но рекурсивный CTE также полезен.

Затем используйте CROSS JOIN, чтобы назначить строки, LEFT JOIN, чтобы ввести нужные значения, а затем GROUP BY, чтобы получить значения:

with dates as (
      select convert(date, '2019-06-01') as dte
      union all
      select dateadd(day, 1, dte) as dte
      from dates
      where dte < '2019-06-15'
     )
select c.city, d.dte, count(t.city)
from (select distinct city from t) c cross join
     dates d left join
     t
     on t.city = c.city and t.start_date <= d.dte and d.end_date >= t.dte 
group by c.city, d.dte
order by c.city, d.dte;

Здесь - это db <> fiddle - с использованием SQL Server.

0 голосов
/ 10 июня 2019
SELECT date,city,count(id) as total FROM table WHERE STR_TO_DATE("2019-06-01","%Y-%m-%d") = STR_TO_DATE("2019-06-01","%Y-%m-%d") GROUP BY city
0 голосов
/ 10 июня 2019

Вы также можете сделать как

DECLARE @MN DATETIME = (SELECT MIN(Start_Date) FROM T),
        @MX DATETIME = (SELECT MAX(End_Date) FROM T);

;WITH CTE AS
(
  SELECT @MN D
  UNION ALL
  SELECT DATEADD(Day, 1, D)
  FROM CTE
  WHERE D <= @MX
)
SELECT TT.City,
       CTE.D [Day],
       (
        SELECT COUNT(1) 
        FROM T T1 
        WHERE T1.City = TT.City 
              AND CTE.D BETWEEN T1.Start_Date AND T1.End_Date
       ) Cnt
FROM CTE CROSS JOIN (VALUES('LA')) TT(City);

Возвраты:

+------+---------------------+-----+
| City |         Day         | Cnt |
+------+---------------------+-----+
| LA   | 01/06/2019 00:00:00 |   1 |
| LA   | 02/06/2019 00:00:00 |   1 |
| LA   | 03/06/2019 00:00:00 |   1 |
| LA   | 04/06/2019 00:00:00 |   0 |
| LA   | 05/06/2019 00:00:00 |   0 |
| LA   | 06/06/2019 00:00:00 |   0 |
| LA   | 07/06/2019 00:00:00 |   1 |
| LA   | 08/06/2019 00:00:00 |   1 |
| LA   | 09/06/2019 00:00:00 |   2 |
| LA   | 10/06/2019 00:00:00 |   2 |
| LA   | 11/06/2019 00:00:00 |   1 |
| LA   | 12/06/2019 00:00:00 |   0 |
| LA   | 13/06/2019 00:00:00 |   1 |
| LA   | 14/06/2019 00:00:00 |   1 |
| LA   | 15/06/2019 00:00:00 |   0 |
+------+---------------------+-----+

Live Demo

0 голосов
/ 10 июня 2019

Попробуйте запрос ниже.Тестовые данные:

DECLARE @tbl TABLE (City varchar(5),Start_Date date,End_Date date);
INSERT INTO @tbl values
( 'LA','2019-06-01','2019-06-03' ),
( 'LA','2019-06-07','2019-06-10' ),
( 'LA','2019-06-09','2019-06-11' ),
( 'LA','2019-06-13','2019-06-14' ),
( 'LO','2019-06-01','2019-06-05' ),
( 'LO','2019-06-04','2019-06-05' ),
( 'LO','2019-06-07','2019-06-09' ),
( 'LO','2019-06-08','2019-06-09' );

Фактический запрос с CTE в качестве функции календаря:

DECLARE @start DATE, @end DATE;
SELECT @start = MIN(Start_Date), @end = MAX(End_Date) FROM @tbl;

;WITH cte AS (
    SELECT @start dt
    UNION ALL
    SELECT DATEADD(day, 1, dt) FROM CTE
    WHERE dt < @end
)

SELECT cte.dt, SUM(CASE WHEN t.City IS NULL THEN 0 ELSE 1 END) FROM cte
LEFT JOIN @tbl t 
ON cte.dt BETWEEN t.Start_Date AND t.End_Date AND t.City = 'LA'
GROUP BY cte.dt
0 голосов
/ 10 июня 2019

Сначала создайте это полезное представление Tally Table

/****** Object:  View [dbo].[cteTally]    Script Date: 10/06/2019 11:02:06 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


CREATE View [dbo].[cteTally] as

WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max

    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )
select N from cteTally


GO

Затем вы можете сгенерировать список дат, о которых вы спрашиваете, вот так (этот запрос ниже для демонстрации, а не для окончательного кодирования)

Declare @Start as date = '20170101';
Declare @End as date = '20190601';

SELECT dateadd(day, N-1,@Start) aDate from [dbo].[cteTally] WHERE  dateadd(day, N-1,@Start) <= @End;

Теперь мы можем расширить это, чтобы подсчитать записи, в которых есть совпадение диапазона дат

SELECT Y.City, DQ.aDate, Count(Y.City) as DayCountForCity FROM (SELECT dateadd(day, N-1,@Start) aDate from [dbo].[cteTally] WHERE  dateadd(day, N-1,@Start) <= @End) DQ
        LEFT JOIN YourTable Y ON DQ.adate BETWEEN Y.Start_Date AND Y.End_Date   
        GRoup By Y.City, DQ.adate

Попробуйте сделать это с вашей заданной тестовой таблицей

Declare @Start as date = '20170101';
Declare @End as date = '20450601';

SELECT * FROM (SELECT Y.City, DQ.aDate, Count(Y.City) as DayCountForCity FROM (SELECT dateadd(day, N-1,@Start) aDate from [dbo].[cteTally] WHERE  dateadd(day, N-1,@Start) <= @End) DQ
        LEFT JOIN Table1 Y ON DQ.adate BETWEEN Y.Start_Date AND Y.End_Date  
        GRoup By Y.City, DQ.adate) Q1 WHERE Q1.city is not null
        order by city, adate
0 голосов
/ 10 июня 2019

Как это должно работать:

select city, '2019-06-11', count(*)
from table1
where end_date >= '2019-06-11'
group by 1

Вы должны заменить дату на переменную и вставить нужную вам дату.

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