Как Разложить период по датам в интервале
Есть дата открытия заявки DataOpen
Есть дата закрытия заявки DataClose.
Необходимо разложить по последнему дню месяца период действия заявки в интервале. Пример
DataOpen - 2021-10-20 DataСlose - 2022-06-17
Нужно разложить в следующем порядке:
2021-10-31
2021-11-30
2021-12-31
2022-01-31
2022-02-28
2022-03-31
2022-04-30
2022-05-31
2022-06-30
В те месяца в которые заявка была открыта - дата раскладывается по последнему дню каждого месяца ,когда заявка была открыта.
Как это сделать в скрипте T SQL MS SQL STUDIO
Скажите пожалуйста.
Ответы (1 шт):
Автор решения: Andrew Nikolaev
→ Ссылка
Написал комментарии для ясности
-- Выбираем нужную на сервере базу данных
USE [YOU_DATABASE_NAME]
GO
-- Это типичные настройки, на них не нужно заострять внимания
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- Если функция с таким именем уже существует на сервере,
-- то мы её удаляем, чтобы создать заново (требуется для того, чтобы
-- было легче править и вносить изменения в эту функцию, иначе пришлось
-- бы писать этот код где то на стороне)
IF EXISTS (
SELECT *
FROM [dbo].[sysobjects]
WHERE id = OBJECT_ID(N'[dbo].[fnt_GetPassengersDate]')
)
DROP FUNCTION [dbo].[fnt_GetPassengersDate]
GO
-- Создаём ТАБЛИЧНУЮ функцию, это говорит о том, что результатом работы
-- будет набор данных, а не скалярное значение
CREATE FUNCTION dbo.fnt_GetPassengersDate
(
@DataOpen DATETIME,
@DateClose DATETIME
)
RETURNS @ResultTable TABLE (Dt DATETIME)
AS
BEGIN
-- Последний день месяца открытия
DECLARE @LastDayOfOpenMonth DATETIME = DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(DAY, 1 - DAY(@DataOpen), @DataOpen)))
-- Последний день месяца закрытия
DECLARE @LastDayOfCloseMonth DATETIME = DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(DAY, 1 - DAY(@DateClose), @DateClose)))
DECLARE @CurrentDate DATETIME = @LastDayOfOpenMonth
WHILE @CurrentDate <= @LastDayOfCloseMonth
BEGIN
INSERT INTO @ResultTable VALUES (@CurrentDate)
SET @CurrentDate = DATEADD(MONTH, 1, @CurrentDate)
SET @CurrentDate = DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(DAY, 1 - DAY(@CurrentDate), @CurrentDate)))
END
RETURN
END
А потом используете её со своей таблицей через CROSS APPLY. Например вот так:
-- Создаём тестовую таблицу, у вас скорее всего будет другая
CREATE TABLE PassangersTable (UserId INT, DateOpen DATETIME, DateClose DATETIME)
-- Заполняем тестовыми данными, выдуманными из головы
INSERT PassangersTable (UserId, DateOpen, DateClose) VALUES
(1, '2021-10-20', '2022-06-17'),
(2, '2021-03-07', '2022-01-12'),
(3, '2022-09-03', '2022-12-23')
SELECT
pt.UserId,
fnt.Dt
FROM PassangersTable pt (NOLOCK)
-- в следующей строке я передаю именно ПОЛЯ исходной таблицы,
-- это будет работать так: на каждого пассажира будут разбиты
-- периоды и все они будут объедены в один набор данных
CROSS APPLY dbo.fnt_GetPassengersDate(pt.DateOpen, pt.DateClose) fnt
-- Удаляем тестовую таблицу
DROP TABLE PassangersTable