Промежуточные даты в sql
Есть таблица выполненных операций orders, в котором хранятся все операции со счетом пользователя т.е зачисление, списание и т.д Выгялдит она соотвественно так.
| id | userId | Date | Summ | Wallet.
| 1 | 72 | 13 | 20 | N .
| 2 | 72 | 13 | 20 | T .
| 3 | 72 | 15 | -20 | N .
| 4 | 72 | 16 | -20 | T .
| 5 | 26 | 15 | 10 | N .
| 6 | 26 | 15 | 10 | T .
| 7 | 26 | 18 | -10 | T .
| 8 | 26 | 21 | -10 | N .
N - не торговый счет.
T - торговый счет.
Задача стоит следущая: Вывести все операции по дням включая промежуточные т.е была операция по счету id = 1 и конец этой операции id=3. Поясняю было зачисление на неторговый счет 20ед. 13 числа, а списание с неторгового счета этого же пользователя было 15 числа. Нужно вывести промежуточные даты включая даты операций т.е 13-14-15.
Написал sql запрос следущего формата:
set @Date1 = '01/01/2022'
set @Date2 = '01/31/2022'
Declare @Date datetime
Select @Date = Convert(datetime, @Date1)
While @Date <= Convert(datetime, @Date2)
Begin
Select userId, @Date As Data, Summ, Wallet, 0 As PaymentSum, 0 As TransitSum
From table
Where Data <= @Date
Select @Date = @Date + 1
End
Результат запроса выводит лишние даты, т.е если по примеру id=1 и id=3 выводит не 13-14-15, а 13-14-15-16-17 и т.д до значения @Date2.
Подскажите как правильно написать запрос, сам в sql не силен и не представляю как решить данный ворос, задачку надо решить именно в sql т.к данные дальше экспортируются в word
Ответы (1 шт):
Попробуйте такой вариант. Немного добавил данных:
| id | userId | Date | Summ | Wallet |
|---|---|---|---|---|
| 1 | 72 | 13 | 20 | N |
| 2 | 72 | 13 | 20 | T |
| 3 | 72 | 15 | -20 | N |
| 4 | 72 | 16 | -20 | T |
| 5 | 26 | 15 | 10 | N |
| 6 | 26 | 15 | 10 | T |
| 7 | 26 | 18 | -10 | T |
| 8 | 26 | 21 | -10 | N |
| 9 | 101 | 2 | 20,00 | N |
| 10 | 101 | 2 | 7,00 | T |
| 11 | 101 | 2 | 20,00 | N |
| 12 | 101 | 5 | -40,00 | N |
| 13 | 101 | 4 | -3,00 | T |
| 14 | 101 | 6 | -4,00 | T |
Код:
-- Задаём период
DECLARE
@Date1 DATETIME = '20220101',
@Date2 DATETIME = '20220131'
-- Создаём табличку с тестовыми данными
DECLARE
@MovementTable TABLE (
Id INT IDENTITY(1,1),
UserId INT,
MoveDate DATETIME, -- нехорошо всё-таки имя столбца date называть, лучше в конце переименуем
Summ MONEY,
Wallet CHAR(1)
)
-- Наполняем тестовыми данными
INSERT @MovementTable
SELECT * FROM (VALUES
(72, '20220113', 20, 'N'),
(72, '20220113', 20, 'T'),
(72, '20220115', -20, 'N'),
(72, '20220116', -20, 'T'),
(26, '20220115', 10, 'N'),
(26, '20220115', 10, 'T'),
(26, '20220118', -10, 'T'),
(26, '20220121', -10, 'N'),
(101, '20220102', 20, 'N'),
(101, '20220102', 7, 'T'),
(101, '20220102', 20, 'N'),
(101, '20220105', -40, 'N'),
(101, '20220104', -3, 'T'),
(101, '20220106', -4, 'T')
) T(UserId, MoveDate, Summ, Wallet)
-- просматривает содержимое тестовых данных, потом удалить
SELECT * FROM @MovementTable
-- Собственно сам запрос
;WITH GenDates AS(
SELECT @Date1 CalcDate
UNION ALL
SELECT CalcDate + 1
FROM GenDates
WHERE CalcDate < @Date2
)
SELECT
MT.Id, -- ид записи в исходной таблице
GroupT.UserId,
MT.CalcDate AS [Date], -- вот тут уже можно переименовать, если этого ворд ждёт
MT.Summ,
GroupT.Wallet
FROM ( -- для каждой пары UserId-Wallet ищём диапазон дат
SELECT UserId, Wallet,
MIN(MoveDate)MinDate,
MAX(MoveDate)MaxDate
FROM @MovementTable MT
GROUP BY UserId, Wallet
) GroupT CROSS APPLY(
-- соединяем с последовательностью дат в этом диапазоне
SELECT MT.*, GD.CalcDate
FROM GenDates GD
LEFT JOIN @MovementTable MT ON GroupT.UserId = MT.UserId AND GroupT.Wallet = MT.Wallet
AND MT.MoveDate = GD.CalcDate
WHERE GD.CalcDate BETWEEN GroupT.MinDate AND GroupT.MaxDate
) MT
-- сортируем
ORDER BY GroupT.UserId, GroupT.Wallet, MT.CalcDate, MT.Id
OPTION (MAXRECURSION 3650)-- 10 лет думаю хватит :)
Результат:
| Id | UserId | Date | Summ | Wallet |
|---|---|---|---|---|
| 5 | 26 | 2022-01-15 00:00:00.000 | 10,00 | N |
| NULL | 26 | 2022-01-16 00:00:00.000 | NULL | N |
| NULL | 26 | 2022-01-17 00:00:00.000 | NULL | N |
| NULL | 26 | 2022-01-18 00:00:00.000 | NULL | N |
| NULL | 26 | 2022-01-19 00:00:00.000 | NULL | N |
| NULL | 26 | 2022-01-20 00:00:00.000 | NULL | N |
| 8 | 26 | 2022-01-21 00:00:00.000 | -10,00 | N |
| 6 | 26 | 2022-01-15 00:00:00.000 | 10,00 | T |
| NULL | 26 | 2022-01-16 00:00:00.000 | NULL | T |
| NULL | 26 | 2022-01-17 00:00:00.000 | NULL | T |
| 7 | 26 | 2022-01-18 00:00:00.000 | -10,00 | T |
| 1 | 72 | 2022-01-13 00:00:00.000 | 20,00 | N |
| NULL | 72 | 2022-01-14 00:00:00.000 | NULL | N |
| 3 | 72 | 2022-01-15 00:00:00.000 | -20,00 | N |
| 2 | 72 | 2022-01-13 00:00:00.000 | 20,00 | T |
| NULL | 72 | 2022-01-14 00:00:00.000 | NULL | T |
| NULL | 72 | 2022-01-15 00:00:00.000 | NULL | T |
| 4 | 72 | 2022-01-16 00:00:00.000 | -20,00 | T |
| 9 | 101 | 2022-01-02 00:00:00.000 | 20,00 | N |
| 11 | 101 | 2022-01-02 00:00:00.000 | 20,00 | N |
| NULL | 101 | 2022-01-03 00:00:00.000 | NULL | N |
| NULL | 101 | 2022-01-04 00:00:00.000 | NULL | N |
| 12 | 101 | 2022-01-05 00:00:00.000 | -40,00 | N |
| 10 | 101 | 2022-01-02 00:00:00.000 | 7,00 | T |
| NULL | 101 | 2022-01-03 00:00:00.000 | NULL | T |
| 13 | 101 | 2022-01-04 00:00:00.000 | -3,00 | T |
| NULL | 101 | 2022-01-05 00:00:00.000 | NULL | T |
| 14 | 101 | 2022-01-06 00:00:00.000 | -4,00 | T |