Ниже я предоставляю код, который в некоторой степени выполняет эту интересную задачу, но может быть плохо спроектирован из-за моих пределов знания SQL. Основная проблема состоит в том, что запрос при выполнении выдает random (точнее 3 разных) результата. Я предполагаю, что строки во вложенных запросах упорядочены по «случайно» выбранному столбцу, и поэтому конечный результат отличается (точка баланса зависит от порядка).
Внутренний SELECT
с GROUP
создает список r-дат и две кумулятивные суммы, например:
rIndex r TotalPerDay CumulativeSum1 CumulativeSum2
1 02.05.2019 92,81 92,81 0
2 03.05.2019 24,81 117,61 0
3 06.05.2019 43,79 161,40 60
4 07.05.2019 78,65 240,05 120
5 09.05.2019 33,99 274,04 180
6 10.05.2019 73,22 347,26 240
7 13.05.2019 19,24 366,50 300
8 14.05.2019 150,77 517,27 360
9 15.05.2019 22,69 539,95 420
10 16.05.2019 4,96 544,91 480
11 17.05.2019 17,45 562,36 540
12 20.05.2019 27,19 589,55 600
13 21.05.2019 12,45 602,00 660
14 22.05.2019 18,08 620,08 720
15 23.05.2019 3,49 623,57 780
16 24.05.2019 10,51 634,09 840
17 27.05.2019 6,19 640,28 900
18 28.05.2019 3,01 643,29 960
19 29.05.2019 2,68 645,97 1020
20 30.05.2019 184,51 830,48 1080
Попытка выборки данных находится во вложении (удалено из-за комментария ниже).
Во втором вложенном SELECT
я нахожу точку баланса, которая является (первой) датой, где CumulativeSum1 > CumulativeSum2
. Затем я должен найти индекс дней с суммами (потому что есть также дни без данных), и это конечный результат; это самый верхний SELECT
в запросе ниже:
DECLARE @eDate as Date
DECLARE @DayLimit INT
SET @DayLimit = 60 -- let's assume a constant here
SET @eDate = DATEFROMPARTS('2019','05','31')
-- get balance point INDEX over non-empty days
SELECT (SELECT COUNT(cDate) FROM Calendar WHERE KindOfDay = 'BANKDAY' AND cDate BETWEEN GETDATE() AND SRC3.BalanceDate) as rIndex
FROM
(
SELECT TOP 1 SRC2.rDate -- get first balance point (date)
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY SRC.rDate) as RowNo
,SRC.rDate
,SRC.TotalPerDay -- not required for processing, included just for info and check
,(SELECT (SUM((eTime-ISNULL(rDura,0))/60)) FROM MyTable1 as MT WHERE MT.r <= SRC.rDate AND MT.r < @eDate) as CumulativeSum1
,((SELECT COUNT(cDate) FROM Calendar WHERE KindOfDay = 'BANKDAY' AND cDate BETWEEN GETDATE() AND SRC.rDate) * @DayLimit) as CumulativeSum2
FROM (
SELECT
CASE
WHEN CAST(r as DATE) < CAST(GETDATE() as date)
THEN DATEADD(dd,-1,CAST(GETDATE() as date))
ELSE CAST(r as date)
END as rDate,
SUM((eTime-ISNULL(rDura,0))/60) as TotalPerDay
FROM MyTable1
WHERE r < @eDate
GROUP BY -- group by non-empty dates, group all past dates to yesterday
CASE
WHEN CAST(r as DATE) < CAST(GETDATE() as date)
THEN DATEADD(dd,-1,CAST(GETDATE() as date))
ELSE CAST(r as date)
END
) as SRC
--ORDER BY rDate
) as SRC2 -- compiled list of sums per day
WHERE SRC2.CumulativeSum2 > SRC2.CumulativeSum1; -- balance condition
) as SRC3
Я скромно прошу предложений по очевидным вопросам:
- как я могу обеспечить порядок строк во вложенном запросе для получения надежного результата?
- есть ли очевидные ошибки в моем дизайне запроса и как его улучшить?
Кроме того, я только что понял, что есть несоответствие в самом верхнем запросе, где я получаю индекс за банковские дни, а индекс должен быть за непустые банковские дни ...
Некоторые примеры данных:
------- CALENDAR TABLE --------------------------------------------------------------------
CREATE TABLE [dbo].[Calendar](
[cDate] [datetime] NOT NULL,
[KindOfDay] [varchar](10) NOT NULL
PRIMARY KEY CLUSTERED
(
[cDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO [dbo].[Calendar] ([cDate],[KindOfDay]) VALUES
('2019-04-20 00:00:00.000', 'SATURDAY'),
('2019-04-21 00:00:00.000', 'SUNDAY'),
('2019-04-22 00:00:00.000', 'HOLIDAY'),
('2019-04-23 00:00:00.000', 'BANKDAY'),
('2019-04-24 00:00:00.000', 'BANKDAY'),
('2019-04-25 00:00:00.000', 'BANKDAY'),
('2019-04-26 00:00:00.000', 'BANKDAY'),
('2019-04-27 00:00:00.000', 'SATURDAY'),
('2019-04-28 00:00:00.000', 'SUNDAY'),
('2019-04-29 00:00:00.000', 'BANKDAY'),
('2019-04-30 00:00:00.000', 'BANKDAY'),
('2019-05-01 00:00:00.000', 'HOLIDAY'),
('2019-05-02 00:00:00.000', 'BANKDAY'),
('2019-05-03 00:00:00.000', 'BANKDAY'),
('2019-05-04 00:00:00.000', 'SATURDAY'),
('2019-05-05 00:00:00.000', 'SUNDAY'),
('2019-05-06 00:00:00.000', 'BANKDAY'),
('2019-05-07 00:00:00.000', 'BANKDAY'),
('2019-05-08 00:00:00.000', 'HOLIDAY'),
('2019-05-09 00:00:00.000', 'BANKDAY'),
('2019-05-10 00:00:00.000', 'BANKDAY'),
('2019-05-11 00:00:00.000', 'SATURDAY'),
('2019-05-12 00:00:00.000', 'SUNDAY'),
('2019-05-13 00:00:00.000', 'BANKDAY'),
('2019-05-14 00:00:00.000', 'BANKDAY'),
('2019-05-15 00:00:00.000', 'BANKDAY'),
('2019-05-16 00:00:00.000', 'BANKDAY'),
('2019-05-17 00:00:00.000', 'BANKDAY'),
('2019-05-18 00:00:00.000', 'SATURDAY'),
('2019-05-19 00:00:00.000', 'SUNDAY'),
('2019-05-20 00:00:00.000', 'BANKDAY'),
('2019-05-21 00:00:00.000', 'BANKDAY'),
('2019-05-22 00:00:00.000', 'BANKDAY'),
('2019-05-23 00:00:00.000', 'BANKDAY'),
('2019-05-24 00:00:00.000', 'BANKDAY'),
('2019-05-25 00:00:00.000', 'SATURDAY'),
('2019-05-26 00:00:00.000', 'SUNDAY'),
('2019-05-27 00:00:00.000', 'BANKDAY'),
('2019-05-28 00:00:00.000', 'BANKDAY'),
('2019-05-29 00:00:00.000', 'BANKDAY'),
('2019-05-30 00:00:00.000', 'BANKDAY'),
('2019-05-31 00:00:00.000', 'BANKDAY'),
('2019-06-01 00:00:00.000', 'SATURDAY'),
('2019-06-02 00:00:00.000', 'SUNDAY'),
('2019-06-03 00:00:00.000', 'BANKDAY'),
('2019-06-04 00:00:00.000', 'BANKDAY'),
('2019-06-05 00:00:00.000', 'BANKDAY'),
('2019-06-06 00:00:00.000', 'BANKDAY'),
('2019-06-07 00:00:00.000', 'BANKDAY'),
('2019-06-08 00:00:00.000', 'SATURDAY'),
('2019-06-09 00:00:00.000', 'SUNDAY'),
('2019-06-10 00:00:00.000', 'BANKDAY'),
('2019-06-11 00:00:00.000', 'BANKDAY'),
('2019-06-12 00:00:00.000', 'BANKDAY'),
('2019-06-13 00:00:00.000', 'BANKDAY'),
('2019-06-14 00:00:00.000', 'BANKDAY'),
('2019-06-15 00:00:00.000', 'SATURDAY'),
('2019-06-16 00:00:00.000', 'SUNDAY'),
('2019-06-17 00:00:00.000', 'BANKDAY'),
('2019-06-18 00:00:00.000', 'BANKDAY'),
('2019-06-19 00:00:00.000', 'BANKDAY'),
('2019-06-20 00:00:00.000', 'BANKDAY')
GO
------- MyTable1 TABLE --------------------------------------------------------------------
CREATE TABLE [dbo].[MyTable1](
[ID] [int] NOT NULL,
[rDate] [date] NOT NULL,
[eTime] [decimal](12,6) NOT NULL,
[rDura] [date] NULL
)
INSERT INTO MyTable1 (ID, rDura, eTime, rDate) VALUES
(17008431,NULL,0.1855,'2019-05-02'),
(17008477,NULL,0.059,'2019-05-02'),
(17008500,NULL,0.329667,'2019-05-02'),
(17090449,NULL,3.3195,'2019-05-02'),
(16888594,NULL,13.830667,'2019-04-26'),
(16888681,NULL,12.6635,'2019-04-26'),
(16888722,NULL,8.154667,'2019-05-07'),
(16888750,NULL,7.83,'2019-05-07'),
(16888766,NULL,5.22,'2019-05-07'),
(16955798,NULL,12.35,'2019-05-07'),
(17108201,NULL,1.669833,'2019-05-07'),
(17110834,NULL,2.596667,'2019-05-02'),
(17111001,NULL,0.814667,'2019-05-06'),
(16893842,NULL,1.053,'2019-05-07'),
(16951779,NULL,2.720833,'2019-05-03'),
(16951821,NULL,4.042333,'2019-05-06'),
(17017058,NULL,0.227333,'2019-05-02'),
(17017060,NULL,1.06,'2019-05-02'),
(17017066,NULL,1.869333,'2019-05-02'),
(17019289,NULL,0.835667,'2019-04-26'),
(17020295,NULL,3.983333,'2019-04-21'),
(17106404,105,3.3545,'2019-04-29'),
(17107843,NULL,2.815167,'2019-05-07'),
(16725584,NULL,0.693,'2019-04-25'),
(17101197,NULL,3.906667,'2019-04-30'),
(17101993,NULL,0.571667,'2019-05-06'),
(17102225,NULL,3.048833,'2019-04-30'),
(17102482,NULL,7.5945,'2019-05-10'),
(16974196,NULL,1.633333,'2019-05-06'),
(17113406,NULL,0.871833,'2019-05-02'),
(17113408,NULL,0.749833,'2019-05-02'),
(17113784,NULL,1.961333,'2019-05-03'),
(17120601,NULL,4.033333,'2019-05-06'),
(17120609,NULL,3.983333,'2019-05-06'),
(17120618,NULL,2.626667,'2019-05-06'),
(17120626,NULL,2.64,'2019-05-06'),
(17120628,NULL,3.684167,'2019-05-06'),
(17121720,NULL,2.235,'2019-04-30'),
(17058455,NULL,5.806667,'2019-04-29'),
(17059476,NULL,2.264833,'2019-05-22'),
(17059478,NULL,182.603667,'2019-05-30'),
(17065386,NULL,5.539667,'2019-05-10'),
(16927091,NULL,1.381,'2019-05-14'),
(16927093,NULL,112.304685,'2019-05-14'),
(16991456,NULL,0.931667,'2019-04-29'),
(17122394,NULL,1.560167,'2019-05-03'),
(17126711,NULL,4.046,'2019-05-03'),
(16935823,NULL,0.359,'2019-04-25'),
(17069727,NULL,1.952833,'2019-05-03'),
(17069870,NULL,1.742333,'2019-05-02'),
(17070555,NULL,5.416667,'2019-05-02'),
(17070557,NULL,3.894167,'2019-05-02'),
(17070851,NULL,2.64,'2019-04-23'),
(17073724,NULL,0.737667,'2019-05-03'),
(17074763,NULL,1.413833,'2019-05-02'),
(17131824,NULL,4.258,'2019-05-10'),
(17132133,NULL,0.257667,'2019-05-14'),
(17132865,NULL,2.769833,'2019-05-17'),
(17138082,NULL,7.866667,'2019-05-31'),
(17139196,NULL,5.860167,'2019-05-03'),
(17139200,NULL,1.479667,'2019-05-03'),
(16983337,NULL,2.951667,'2019-05-02'),
(17028542,NULL,0.680333,'2019-05-13'),
(16823160,NULL,5,'2019-05-06'),
(16823168,NULL,5,'2019-05-06'),
(16823182,NULL,5,'2019-05-06'),
(16823192,NULL,5,'2019-05-06'),
(16906776,NULL,0.8635,'2019-05-02'),
(17082286,NULL,3.333333,'2019-05-09'),
(17083776,NULL,2.317167,'2019-04-25'),
(17083778,NULL,1.447167,'2019-05-02'),
(17084568,NULL,0.2375,'2019-05-02'),
(17154415,NULL,2.64,'2019-05-14'),
(17154425,NULL,2.626667,'2019-05-14'),
(17154453,NULL,0.052,'2019-05-06'),
(17155029,NULL,3.256667,'2019-05-22'),
(17157159,NULL,1.333333,'2019-05-15'),
(16994233,NULL,0.252167,'2019-04-29'),
(17039767,NULL,1.401667,'2019-05-10'),
(17040346,NULL,4.021667,'2019-05-09'),
(17040815,NULL,1.2675,'2019-05-16'),
(17042063,NULL,0.213333,'2019-05-03'),
(17050144,NULL,0.976667,'2019-05-02'),
(17050150,NULL,0.837167,'2019-05-20'),
(17051422,NULL,1.826,'2019-05-07'),
(17142464,NULL,0.464333,'2019-05-06'),
(17145501,NULL,4.745333,'2019-06-06'),
(17145980,NULL,0.195167,'2019-05-07'),
(17145999,NULL,1.330833,'2019-05-07'),
(17146001,NULL,1.503833,'2019-05-06'),
(17146011,NULL,1.22,'2019-05-03'),
(17146017,NULL,0.373,'2019-05-07'),
(17146023,NULL,0.5745,'2019-05-03'),
(17146127,NULL,1.7835,'2019-05-15'),
(17146131,NULL,13.5595,'2019-05-07'),
(17152617,NULL,4.535667,'2019-05-10'),
(17154390,NULL,3.983333,'2019-05-14'),
(17154398,NULL,5.416667,'2019-05-14'),
(17154400,NULL,3.684167,'2019-05-14')
GO