Как сделать этот код многоразовым в SQL Server 2016 (кроме Union all) - PullRequest
1 голос
/ 16 апреля 2019

Я пытаюсь привязать данные к прошлому. Скажем, сегодня в таблице сотрудников, когда я щелкаю, я вижу количество 1000 сотрудников. Но это было не так вчера. Сегодня к нам присоединились 2 новых сотрудника, следовательно, я получаю счет 1000. Если я захочу получить вчерашний день, я должен получить 998 и так далее за последние 60 дней.

Я попробовал UNION ALL. Но это не поможет в течение большего количества дней.

/* Create Table */

CREATE TABLE dbo.EMPTable (ID INT, H_Date DATE)

/* Load Data */
INSERT INTO dbo.EMPTable VALUES (1,'2019-04-17')
INSERT INTO dbo.EMPTable VALUES (2,'2019-04-17')
INSERT INTO dbo.EMPTable VALUES (3,'2019-04-16')
INSERT INTO dbo.EMPTable VALUES (4,'2019-04-16')
INSERT INTO dbo.EMPTable VALUES (5,'2019-04-15')
INSERT INTO dbo.EMPTable VALUES (6,'2019-04-15')
INSERT INTO dbo.EMPTable VALUES (7,'2019-04-15')
INSERT INTO dbo.EMPTable VALUES (8,'2019-04-14')
INSERT INTO dbo.EMPTable VALUES (9,'2019-04-14')
INSERT INTO dbo.EMPTable VALUES (10,'2019-04-14')
INSERT INTO dbo.EMPTable VALUES (11,'2019-04-14')
INSERT INTO dbo.EMPTable VALUES (12,'2019-04-14')
INSERT INTO dbo.EMPTable VALUES (13,'2019-04-13')
INSERT INTO dbo.EMPTable VALUES (14,'2019-04-13')
INSERT INTO dbo.EMPTable VALUES (15,'2019-04-13')
INSERT INTO dbo.EMPTable VALUES (16,'2019-04-13')
INSERT INTO dbo.EMPTable VALUES (17,'2019-04-13')
INSERT INTO dbo.EMPTable VALUES (16,'2019-04-11')
INSERT INTO dbo.EMPTable VALUES (17,'2019-04-11')

--SELECT * FROM dbo.EMPTable

/* Long query */
SELECT 
CAST(GETDATE()-6 AS DATE) AS Snap_Date, 
COUNT(ID) AS I_Count
FROM dbo.EMPTable
WHERE H_Date >=CAST((GETDATE()-6) -3 AS DATE) AND H_Date <= CAST((GETDATE()-6)  AS DATE)
UNION ALL
SELECT 
CAST(GETDATE()-5 AS DATE) AS Snap_Date, 
COUNT(ID) AS I_Count
FROM dbo.EMPTable
WHERE H_Date >=CAST((GETDATE()-5)  -3 AS DATE) AND H_Date <= CAST((GETDATE()-5)  AS DATE)
UNION ALL
SELECT 
CAST(GETDATE()-4 AS DATE) AS Snap_Date, 
COUNT(ID) AS I_Count
FROM dbo.EMPTable
WHERE H_Date >=CAST((GETDATE()-4) -3 AS DATE) AND H_Date <= CAST((GETDATE()-4)  AS DATE)
UNION ALL
SELECT 
CAST(GETDATE()-3 AS DATE) AS Snap_Date, 
COUNT(ID) AS I_Count
FROM dbo.EMPTable
WHERE H_Date >=CAST((GETDATE()-3)  -3 AS DATE) AND H_Date <= CAST((GETDATE()-3)  AS DATE)
UNION ALL
SELECT 
CAST(GETDATE()-2 AS DATE) AS Snap_Date, 
COUNT(ID) AS I_Count
FROM dbo.EMPTable
WHERE H_Date >=CAST((GETDATE()-2)  -3 AS DATE) AND H_Date <= CAST((GETDATE()-2)  AS DATE)
UNION ALL
SELECT 
CAST(GETDATE()-1 AS DATE) AS Snap_Date, 
COUNT(ID) AS I_Count
FROM dbo.EMPTable
WHERE H_Date >=CAST((GETDATE()-1)  -3 AS DATE) AND H_Date <= CAST((GETDATE()-1)  AS DATE)
UNION ALL
SELECT 
CAST(GETDATE() AS DATE) AS Snap_Date, 
COUNT(ID) AS I_Count
FROM dbo.EMPTable
WHERE H_Date >=CAST((GETDATE())  -3 AS DATE)
--------------------------
Expected Result
--------------------------
Snap_Date   I_Count
2019-04-11  2
2019-04-12  2
2019-04-13  7
2019-04-14  12
2019-04-15  13
2019-04-16  15
2019-04-17  12

Если вы видите сейчас, я делаю снимок за последние 3 дня с сегодняшнего дня. Приходить вчера снова последние 3 дня со вчерашнего дня и так далее. Кроме того, мы не можем принять H_Date как Snap_Date, потому что если одна из дат не имеет наемных работников. Дескать, на 2019-04-12 не было ни одного наемного работника. Тогда эта конкретная дата не будет доступна, если принять H_Date за Snap_Date.

Мои извинения. Основываясь на решениях, которые я вижу, мне было неясно от моего имени полное изложение проблемы. Надеюсь теперь понятно.

Ответы [ 2 ]

6 голосов
/ 16 апреля 2019

Сначала создайте таблицу календаря с достаточно большим диапазоном дат для будущих нужд

CREATE TABLE dbo.Calendar (Date DATE PRIMARY KEY)

--2010-01-01 TO 2039-12-31 inclusive. Adjust as needed
INSERT INTO dbo.Calendar
SELECT TOP (10957) DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY @@SPID), '2009-12-31')
FROM sys.all_objects o1, sys.all_objects o2;

Затем вы можете присоединиться к ней, чтобы получить недостающие даты, как показано ниже

SELECT C.Date, 
       SUM(COUNT(E.ID))  OVER (ORDER BY C.Date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS I_Count
FROM dbo.Calendar C
LEFT JOIN dbo.EMPTable E ON E.H_Date = C.Date
WHERE C.Date BETWEEN '2019-04-11' AND CAST(GETDATE() AS DATE)
GROUP  BY C.Date

План выполнения этого довольно эффективен. Пример ниже (с индексом dbo.EMPTable(H_Date) INCLUDE(ID))

enter image description here

1 голос
/ 16 апреля 2019

Хм, если честно, я не совсем понимаю ваш пост.Но чтобы получить ожидаемый результат из данных данного примера, вы можете объединить записи с более ранними или равными h_date с набором различных h_date s, затем сгруппировать по дате и взять счетчик.

SELECT e1.h_date snap_date,
       coalesce(count(*), 0) i_count
       FROM (SELECT DISTINCT
                    e1.h_date
                    FROM emptable e1) e1
            INNER JOIN emptable e2
                       ON e2.h_date <= e1.h_date
       GROUP BY e1.h_date;

Если вы ожидаете, что есть дни, когда никто не присоединился, поэтому у вас был пробел в серии дней, вы также можете использовать рекурсивный CTE для получения набора данных.Затем используйте левое соединение и посчитайте h_date.

WITH
cte
AS
(
SELECT 0 n
UNION ALL
SELECT n + 1 n
       FROM cte
       WHERE n + 1 <= 4
)
SELECT e1.h_date snap_date,
       count(e2.h_date) i_count
       FROM (SELECT convert(date, dateadd(day, -c.n, '2019-04-17')) h_date
                    FROM cte c) e1
            LEFT JOIN emptable e2
                      ON e2.h_date <= e1.h_date
       GROUP BY e1.h_date;

(измените дату начала и количество дней, чтобы вернуться в соответствии с вашими потребностями.)

дБ<> скрипка

...