Я пишу оператор Select, и по соображениям читабельности и ясности я использую переменные / переменные таблицы внутри - в этом конкретном контексте это значительно упрощает понимание кода.
Поскольку я использую переменные, яя не могу сохранить этот выбор как VIEW
, и мне интересно, если сделать это Stored Procedure
правильным способом.
Я знаю, что я мог бы построить представление по-другому, используя функции с табличными значениями и т. д. , но для меня важно, чтобы все «решение» содержалось в одном объекте SQL (простота развертывания между средами, отслеживаемость).
Правильный ли тогда путь Stored Procedure
? Или он не должен использоваться в качестве замены для представлений?
КОД:
-- Supporting tables
DECLARE @Years TABLE (Year INT)
DECLARE @RevenueInTime TABLE (
[RequestID] [nvarchar](20) NULL,
[StartDate] [datetime] NULL,
[Duration] [bigint] NULL,
[OneTime] [bigint] NULL,
[Monthly] [bigint] NULL,
[year] [bigint] NULL,
[m1] [bigint] NULL,
[m2] [bigint] NULL,
[m3] [bigint] NULL,
[m4] [bigint] NULL,
[m5] [bigint] NULL,
[m6] [bigint] NULL,
[m7] [bigint] NULL,
[m8] [bigint] NULL,
[m9] [bigint] NULL,
[m10] [bigint] NULL,
[m11] [bigint] NULL,
[m12] [bigint] NULL
)
DECLARE @Revenue TABLE(
[RequestID] [varchar](255) NULL,
[StartDate] [datetime] NULL,
[DurationInMonths] [bigint] NULL,
[Rev_OneTime] [bigint] NULL,
[Rev_Monthly] [int] NULL
)
DECLARE @CurrYear INT
DECLARE @MinYear INT
DECLARE @MaxYear INT
;
/*
Create Table holding esseintal information about each Request (record per Request)
ID, StartDate, Duration, One-Time Revenue, Monthly Revenue
*/
WITH OneTime AS (
SELECT
RequestId,
ROUND(SUM(Revenue), 0) AS Rev_OneTime
FROM costs
WHERE NonRecurring = 'Y'
GROUP BY RequestId
),
Reccuring_one AS (
SELECT
RequestId,
SUM(Revenue) AS Rev_Reccuring,
MAX(DurationInMonths) AS Duration
FROM costs
WHERE NonRecurring = 'N'
GROUP BY RequestId
),
Recurring AS (
SELECT
RequestId,
CASE
WHEN Duration = 0 THEN 0
ELSE ROUND(Rev_Reccuring / Duration, 0 )
END AS Rev_Monthly
FROM Reccuring_one
),
DistRequests AS (
SELECT
DISTINCT RequestID, StartDate, DurationInMonths
FROM costs
), Revenue AS (
SELECT
DR.RequestID,
DR.StartDate,
DR.DurationInMonths,
ISNULL(CAST(OT.Rev_OneTime AS bigint), 0) AS Rev_OneTime,
ISNULL(CAST(R.Rev_Monthly AS INT), 0 ) AS Rev_Monthly
FROM DistRequests DR
LEFT JOIN OneTime OT ON DR.RequestId = OT.RequestId
LEFT JOIN Recurring R ON DR.RequestId = R.RequestId
)
INSERT INTO @Revenue SELECT * FROM Revenue
-- Calculate Timeframe that should be in scope, i.e year of minimum start date - untill year of maxiumm end date
SET @MinYear = (SELECT MIN(YEAR(StartDate)) FROM @Revenue)
SET @MaxYear = (SELECT MAX(YEAR(DATEADD(MONTH,DurationInMonths,StartDate))) FROM @Revenue)
SET @CurrYear = @MinYear
-- Table populated with each consecutive year for examined period
WHILE @CurrYear <= @MaxYear
BEGIN
INSERT INTO @Years VALUES (@CurrYear)
SET @CurrYear = @CurrYear + 1
END
SET @CurrYear = @MinYear
;
-- Loop through each year, and create record for each requests that is ongoing during it
DECLARE year_cursor CURSOR FOR
SELECT Year FROM @Years
OPEN year_cursor
FETCH NEXT FROM year_cursor INTO @CurrYear
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO @RevenueInTime
(
[RequestID]
,[StartDate]
,[Duration]
,[OneTime]
,[Monthly]
,[year]
,[m1]
,[m2]
,[m3]
,[m4]
,[m5]
,[m6]
,[m7]
,[m8]
,[m9]
,[m10]
,[m11]
,[m12]
)
SELECT
RequestID,
StartDate,
DurationInMonths,
Rev_OneTime,
Rev_Monthly,
@CurrYear AS year,
--If inspected month is between StartDate and End Date of project set RevenueMonthly, else set 0
--Use EOMONTH to make sure that all Requests regardless of DAY of StartDate qualify
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 1, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 2, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 3, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 4, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 5, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 6, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 7, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 8, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 9, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 10, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 11, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end,
CASE WHEN EOMONTH(DATEFROMPARTS(@CurrYear, 12, 1)) BETWEEN StartDate AND DATEADD(MONTH,DurationInMonths ,StartDate) then Rev_Monthly else 0 end
FROM @Revenue
WHERE YEAR(StartDate) <= @CurrYear AND YEAR(DATEADD(MONTH,DurationInMonths,StartDate)) >= @CurrYear
FETCH NEXT FROM year_cursor INTO @CurrYear
END
CLOSE year_cursor
DEALLOCATE year_cursor
SELECT
RIT.*
FROM @RevenueInTime RIT