sql - 仅仅因为我想在代码中包含变量而使用存储过程而不是视图是否合理?
问题描述
我正在编写一个 Select 语句,出于可读性和清晰性的原因,我在内部使用了变量/表变量——在这个特定的上下文中,它使编码更容易理解。
由于我使用的是变量,因此我无法将此选择存储为VIEW
,并且我想知道将其设为 aStored 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
解决方案
推荐阅读
- c# - c# [OnPrem CRM] 中的 Dynamics crm retrieveEntityReq (Javascript) 函数
- squid - 带有 SSLbump 和身份验证 403 的 Squid。这是一个封装的请求,不进行身份验证
- ios - 无法设置收集单元
- angular - ng2-chart 仅在光标位于某个位置时刷新
- selenium - Nightwatch 没有获取 sendkeys 值
- xml - 使用 XSLT 提取和更新 XML
- android - 在基于 MVVM 的应用程序中添加 Room Database 类会产生绑定问题
- ruby-on-rails - 如何在 Active Storage 中仅存储 .yml 文件
- java - 变量是从内部类中访问的,需要声明为final
- sql - Oracle Apex:根据条件在报告中创建红绿灯