英文:
Stored procedure with datetime
问题
我创建了一个带有以下数据集的表格
创建表 [dbo].[RiskTable]
(
[ReqID] [int] NOT NULL,
[ModuleName] [nvarchar](50) NULL,
[CreatedDate] [datetime2](7) NULL,
[AssociatedRisk] [nvarchar](50) NULL
)
模型 | 关联风险 | 创建日期 |
---|---|---|
IDP | 高 | 2022-12-18 00:00:00.0000000 |
Saa | 高 | 2023-01-02 00:00:00.0000000 |
Saa | 中 | 2023-01-07 00:00:00.0000000 |
Saa | 严重 | 2023-01-29 00:00:00.0000000 |
Saa | 低 | 2023-02-05 00:00:00.0000000 |
Saa | 低 | 2023-02-07 00:00:00.0000000 |
EEE | 严重 | 2023-03-09 00:00:00.0000000 |
信息 | 低 | 2023-04-08 00:00:00.0000000 |
IDP | 高 | 2023-04-28 00:00:00.0000000 |
IDP | 中 | 2023-05-08 00:00:00.0000000 |
此表包含模型、风险和创建日期。
我尝试编写了一个存储过程,其中包含一些条件。
- 如果我给定模型 = saa,start_date = 2023-01-01,end_date = 2023-02-10,则希望显示该模型“saa”在这些特定月份(2023-01-01(一月),2023-02-10(二月))的所有风险(低、中、高和严重)的总数。
它必须为我提取如下数据:
模型 | 月份 | 风险 | 风险总数 |
---|---|---|---|
Saa | 一月或 01 | 低 | 0 |
Saa | 一月或 01 | 中 | 1 |
Saa | 一月或 01 | 高 | 1 |
Saa | 一月或 01 | 严重 | 1 |
Saa | 二月或 02 | 低 | 2 |
Saa | 二月或 02 | 中 | 0 |
Saa | 二月或 02 | 高 | 0 |
Saa | 二月或 02 | 严重 | 0 |
- 如果我给定模型 = Null,start_date = 2023-04-01,end_date = 2023-05-11,则希望显示所有模型在这些特定月份(2023-04-01(四月),2023-05-11(五月))的所有风险(低、中、高和严重)的总数。
它必须为我提取如下数据:
模型 | 月份 | 风险 | 风险总数 |
---|---|---|---|
所有 | 四月或 04 | 低 | 1 |
所有 | 四月或 04 | 中 | 0 |
所有 | 四月或 04 | 高 | 1 |
所有 | 四月或 04 | 严重 | 0 |
所有 | 五月或 05 | 低 | 0 |
所有 | 五月或 05 | 中 | 1 |
所有 | 五月或 05 | 高 | 0 |
所有 | 五月或 05 | 严重 | 0 |
我尝试编写了两个存储过程:
创建存储过程 Month_base
AS
SELECT
月份(CreatedDate) 月份,
COUNT(CASE WHEN AssociatedRisk = '低' THEN 1 END) AS 低,
COUNT(CASE WHEN AssociatedRisk = '中' THEN 1 END) AS 中,
COUNT(CASE WHEN AssociatedRisk = '高' THEN 1 END) AS 高,
COUNT(CASE WHEN AssociatedRisk = '严重' THEN 1 END) AS 严重
FROM
RiskTable
WHERE
年份(CreatedDate) ='2023'
GROUP BY
月份(CreatedDate)
执行 Month_base
接下来的存储过程带有一个 if
条件。
ALTER PROCEDURE avgg_calc
@model_name nvarchar(max) = NULL,
@start_date datetime2 = NULL,
@end_date datetime2 = NULL
AS
DECLARE @sql nvarchar(max);
-- 必须调用另一个存储过程并创建临时表
SET @sql = 'WHERE 1 = 1';
IF @model_name IS NOT NULL
SET @sql += '
AND Model = @_model_name';
IF @start_date IS NOT NULL
SET @sql += '
AND CreatedDate >= @_start_date';
IF @end_date IS NOT NULL
SET @sql += '
AND CreatedDate < @_end_date';
打印 @sql;
这就是我尝试过的,感觉走错了方向。我必须使用 while
来解决这个问题,但我不确定如何为这些条件编写查询。
可以有人帮我编写一个包括这些条件的存储过程查询吗?
英文:
I have created a table with the following set of data
CREATE TABLE [dbo].[RiskTable]
(
    [ReqID] [int] NOT NULL,
    [ModuleName] [nvarchar](50) NULL,
    [CreatedDate] [datetime2](7) NULL,
    [AssociatedRisk] [nvarchar](50) NULL
)
Model | AssociatedRisk | Created Date |
---|---|---|
IDP | High | 2022-12-18 00:00:00.0000000 |
Saa | High | 2023-01-02 00:00:00.0000000 |
Saa | Medium | 2023-01-07 00:00:00.0000000 |
Saa | Critical | 2023-01-29 00:00:00.0000000 |
Saa | Low | 2023-02-05 00:00:00.0000000 |
Saa | Low | 2023-02-07 00:00:00.0000000 |
EEE | Critical | 2023-03-09 00:00:00.0000000 |
Info | Low | 2023-04-08 00:00:00.0000000 |
IDP | High | 2023-04-28 00:00:00.0000000 |
IDP | Medium | 2023-05-08 00:00:00.0000000 |
This table has the model, risk, and created date.
I have tried to write a stored procedure with a few conditions like
- If I'm giving model = saa, start_date = 2023-01-01, end_date = 2023-02-10, I want it to show me the total number of risks (low, Medium, High, and Critical) of those particular months (2023-01-01(Jan), 2023-02-10(Feb)) of the model 'saa'.
It has to fetch me data like this:
Model | Month | Risk | Total no. of risk |
---|---|---|---|
Saa | Jan or 01 | Low | 0 |
Saa | Jan or 01 | Medium | 1 |
Saa | Jan or 01 | High | 1 |
Saa | Jan or 01 | Critical | 1 |
Saa | Feb or 02 | Low | 2 |
Saa | Feb or 02 | Medium | 0 |
Saa | Feb or 02 | High | 0 |
Saa | Feb or 02 | Critical | 0 |
- If I'm giving model = Null, start_date = 2023-04-01, end_date = 2023-05-11, I want it to show me the total number of risks (low, Medium, High, and Critical) of those particular months (2023-04-01(Apr), 2023-05-11(May)) of all the models.
It has to fetch me data like this :
Model | Month | Risk | Total no. of risk |
---|---|---|---|
All | Apr or 04 | Low | 1 |
All | Apr or 04 | Medium | 0 |
All | Apr or 04 | High | 1 |
All | Apr or 04 | Critical | 0 |
All | May or 05 | Low | 0 |
All | May or 05 | Medium | 1 |
All | May or 05 | High | 0 |
All | May or 05 | Critical | 0 |
I tried to write 2 stored procedures:
CREATE PROCEDURE Month_base
AS
SELECT
MONTH(CreatedDate) MONTH,
COUNT(CASE WHEN AssociatedRisk = 'Low' THEN 1 END) AS Low,
COUNT(CASE WHEN AssociatedRisk = 'Medium' THEN 1 END) AS Medium,
COUNT(CASE WHEN AssociatedRisk = 'High' THEN 1 END) AS High,
COUNT(CASE WHEN AssociatedRisk = 'Critical' THEN 1 END) AS Critical
FROM
RiskTable
WHERE
YEAR(CreatedDate) ='2023'
GROUP BY
MONTH(CreatedDate)
EXEC Month_base
Next stored procedure with an if
condition.
ALTER PROCEDURE avgg_calc
@model_name nvarchar(max) = NULL,
@start_date datetime2 = NULL,
@end_date datetime2 = NULL
AS
DECLARE @sql nvarchar(max);
-- have to call another stored procedure and create temporary table
SET @sql = 'WHERE 1 = 1';
IF @model_name IS NOT NULL
SET @sql += '
AND Model = @_model_name';
IF @start_date IS NOT NULL
SET @sql += '
AND CreatedDate >= @_start_date';
IF @end_date IS NOT NULL
SET @sql += '
AND CreatedDate < @_end_date';
PRINT @sql;
This is what I have tried, it feels like I'm on the wrong track. I have to use while
to get it, but I exactly don't know how to write a query for these conditions.
Can someone help me in writing a stored procedure query including these conditions?
答案1
得分: 1
Here is the translated code:
**EDIT:** 我根据要求更新了我的脚本。我内联添加了一些注释。我认为使用临时表会更清晰。
DECLARE @startDate DateTime = '2023-04-01'
DECLARE @endDate DateTime = '2023-05-30'
DECLARE @model varchar(50) = 'IDP' -- 或者替换为模型名称 'Saa'
-- 创建3个不同的表,用于RiskNames、Modules和MonthsBetween开始和结束日期之间的所有月份,以创建它们的笛卡尔积。
-- RISKS表还包含将在最终SELECT的ORDER BY子句中使用的ORDER。
DECLARE @distinctRisks Table (RiskName varchar(50), RiskOrder int)
INSERT INTO @distinctRisks (RiskName, RiskOrder)
SELECT '低', 1
UNION SELECT '中', 2
UNION SELECT '高', 3
UNION SELECT '关键', 4
-- Modules表包含所有可能的模块(或模型.. 对我来说不太清楚)
DECLARE @distinctModules Table (ModuleName varchar(50))
INSERT INTO @distinctModules (ModuleName)
SELECT DISTINCT ModuleName from dbo.RiskTable
-- Months表包含开始和结束日期之间的所有月份。 这次我还包括了年份,以适应搜索跨越多年的情况。
DECLARE @distinctMonths Table (MonthAndYear varchar(10)) ;
with months (date)
AS
(
SELECT @startDate
UNION ALL
SELECT DATEADD(month, 1, date)
from months
where DATEADD(month, 1, date) <= @endDate
)
INSERT INTO @distinctMonths (MonthAndYear)
SELECT FORMAT(date, 'MM-yyyy')
from months
-- 现在使用这3个表并创建一个Risk X Modules X Months的笛卡尔积
DECLARE @distinctRisksModulesAndMonths Table
(
RiskName nvarchar(50),
RiskOrder int,
ModuleName nvarchar(50),
MonthAndYear varchar(10)
)
INSERT INTO @distinctRisksModulesAndMonths (RiskName, RiskOrder, ModuleName, MonthAndYear)
SELECT r.RiskName, r.RiskOrder, m.ModuleName, my.MonthAndYear
FROM @distinctRisks r
CROSS JOIN @distinctModules m
CROSS JOIN @distinctMonths my
-- 这是包含原始SELECT结果的表
DECLARE @values Table
(
ModuleName nvarchar(50),
RiskName nvarchar(50),
MonthAndYear varchar(10),
RiskCount int
)
insert into @values(ModuleName, RiskName, MonthAndYear, RiskCount )
SELECT
ModuleName,
AssociatedRisk,
FORMAT(CreatedDate, 'MM-yyyy'),
COUNT(1) as RiskCount
FROM [dbo].[RiskTable]
WHERE (@model is null or ModuleName = @model)
AND @startDate <= CreatedDate and CreatedDate <= @endDate
GROUP BY FORMAT(CreatedDate, 'MM-yyyy'), AssociatedRisk, ModuleName
select * from @values
-- 最终结果
SELECT
m.ModuleName,
m.RiskName,
m.MonthAndYear,
ISNULL(c.RiskCount, 0)
FROM @distinctRisksModulesAndMonths m
LEFT JOIN @values c
on c.RiskName = m.RiskName
and c.ModuleName = m.ModuleName
and c.MonthAndYear = m.MonthAndYear
where @model is null or m.ModuleName = @model
order by MonthAndYear, RiskOrder
你可以将此代码转换为存储过程:
CREATE PROCEDURE GetRiskPerMonth
(
@startDate DateTime,
@endDate DateTime,
@model varchar(50) = NULL
)
AS
BEGIN
SELECT ...
END
然后使用以下方式调用它:
Exec GetRiskPerMonth '2023-04-01', '2023-04-30', 'IDP'
或者只需
Exec GetRiskPerMonth '2023-04-01', '2023-04-30'
英文:
EDIT: I've updated my script according to the requirements. I've added some comments inline. I think that using temporary tables makes it clearer.
DECLARE @startDate DateTime = '2023-04-01'
DECLARE @endDate DateTime = '2023-05-30'
DECLARE @model varchar(50) = 'IDP' -- or replace with a model name 'Saa'
-- CREATE 3 distinct tables for RiskNames, Modules and MonthsBetween start and end date
-- with the intention to CREATE a CARTESIAN PRODUCT out of them.
--The RISKS table also contains the ORDER which will be used in the Order by Clause of the final SELECT
DECLARE @distinctRisks Table (RiskName varchar(50), RiskOrder int)
INSERT INTO @distinctRisks (RiskName, RiskOrder)
SELECT 'Low', 1
UNION SELECT 'Medium', 2
UNION SELECT 'High', 3
UNION SELECT 'Critical',4
-- Modules table contains all the possible modules (or models.. this is not very clear for me)
DECLARE @distinctModules Table (ModuleName varchar(50))
INSERT INTO @distinctModules (ModuleName)
SELECT DISTINCT ModuleName from dbo.RiskTable
-- Months table contains all the months between start and end date.
-- This time I've included the Year as well helps to accomodate the case when the search spans on multiple years
DECLARE @distinctMonths Table (MonthAndYear varchar(10))
;with months (date)
AS
(
SELECT @startDate
UNION ALL
SELECT DATEADD(month, 1, date)
from months
where DATEADD(month, 1, date) <= @endDate
)
INSERT INTO @distinctMonths (MonthAndYear)
SELECT FORMAT(date, 'MM-yyyy')
from months
-- Now use the 3 tables and create a cartesian product Risks X Modules X Months
DECLARE @distinctRisksModulesAndMonths Table
(
RiskName nvarchar(50),
RiskOrder int,
ModuleName nvarchar(50),
MonthAndYear varchar(10)
)
INSERT INTO @distinctRisksModulesAndMonths (RiskName, RiskOrder, ModuleName, MonthAndYear)
SELECT r.RiskName, r.RiskOrder, m.ModuleName, my.MonthAndYear
FROM @distinctRisks r
CROSS JOIN @distinctModules m
CROSS JOIN @distinctMonths my
-- This is the table that will contain the results from the original select
DECLARE @values Table
(
ModuleName nvarchar(50),
RiskName nvarchar(50),
MonthAndYear varchar(10),
RiskCount int
)
insert into @values(ModuleName, RiskName, MonthAndYear, RiskCount )
SELECT
ModuleName,
AssociatedRisk,
FORMAT(CreatedDate, 'MM-yyyy'),
COUNT(1) as RiskCount
FROM [dbo].[RiskTable]
WHERE (@model is null or ModuleName = @model)
AND @startDate <= CreatedDate and CreatedDate <= @endDate
GROUP BY FORMAT(CreatedDate, 'MM-yyyy'), AssociatedRisk, ModuleName
select * from @values
--FINAL RESULT
SELECT
m.ModuleName,
m.RiskName,
m.MonthAndYear,
ISNULL(c.RiskCount, 0)
FROM @distinctRisksModulesAndMonths m
LEFT JOIN @values c
on c.RiskName = m.RiskName
and c.ModuleName = m.ModuleName
and c.MonthAndYear = m.MonthAndYear
where @model is null or m.ModuleName = @model
order by MonthAndYear, RiskOrder
You can transform this to a stored procedure:
CREATE PROCEDURE GetRiskPerMonth
(
@startDate DateTime,
@endDate DateTime,
@model varchar(50) = NULL
)
AS
BEGIN
SELECT ...
END
Then call it with
Exec GetRiskPerMonth '2023-04-01', '2023-04-30', 'IDP'
or just
Exec GetRiskPerMonth '2023-04-01', '2023-04-30'
答案2
得分: 0
这个查询将处理两种情况,如果传入ALL
,存储过程将检索按月份和风险分组的数据,如果传入模块,结果将按月份、风险和模块分组。
CREATE PROCEDURE Month_base_global
@model varchar(20),
@start_date date,
@end_date date
AS
IF @model = 'ALL'
BEGIN
SELECT 'ALL' as [Module], ac.[Month], ac.AssociatedRisk as Risk, count(ri.ModuleName) as 'Total risks'
FROM (
SELECT DISTINCT convert(varchar(7), r.CreatedDate, 126) as [month], a.AssociatedRisk, m.ModuleName
FROM RiskTable r
FULL OUTER JOIN (
SELECT DISTINCT AssociatedRisk
FROM RiskTable
) as a on a.AssociatedRisk is not null
FULL OUTER JOIN (
SELECT DISTINCT ModuleName
FROM RiskTable
) as m on m.ModuleName is not null
WHERE MONTH(r.CreatedDate) between MONTH(@start_date) and MONTH(@end_date)
) as ac
LEFT JOIN RiskTable ri on ac.[month] = convert(varchar(7), ri.CreatedDate, 126)
and ac.AssociatedRisk = ri.AssociatedRisk
GROUP BY ac.[month], ac.AssociatedRisk
ORDER BY ac.[month], ac.AssociatedRisk desc
END
ELSE
BEGIN
SELECT @model as [Module], ac.[Month], ac.AssociatedRisk as Risk, count(ri.ModuleName) as 'Total risks'
FROM (
SELECT DISTINCT convert(varchar(7), r.CreatedDate, 126) as [month], a.AssociatedRisk, m.ModuleName
FROM RiskTable r
FULL OUTER JOIN (
SELECT DISTINCT AssociatedRisk
FROM RiskTable
) as a on a.AssociatedRisk is not null
FULL OUTER JOIN (
SELECT DISTINCT ModuleName
FROM RiskTable
) as m on m.ModuleName = @model
WHERE r.CreatedDate between DATEADD(mm, DATEDIFF(mm, 0, @start_date), 0) and eomonth(@end_date)
) as ac
LEFT JOIN RiskTable ri on ac.[month] = convert(varchar(7), ri.CreatedDate, 126)
and ac.AssociatedRisk = ri.AssociatedRisk
GROUP BY ac.ModuleName, ac.[month], ac.AssociatedRisk
ORDER BY ac.[month], ac.AssociatedRisk desc
END
英文:
This query will handle both cases, if ALL
is passed, the proc will retrieve data grouped by month and risk, and if a module is passed, the result will be grouped by month, risk, and module.
CREATE PROCEDURE Month_base_global
@model varchar(20),
@start_date date,
@end_date date
AS
IF @model = 'ALL'
BEGIN
SELECT 'ALL' as [Module], ac.[Month], ac.AssociatedRisk as Risk, count(ri.ModuleName) as 'Total risks'
FROM (
SELECT DISTINCT convert(varchar(7), r.CreatedDate, 126) as [month], a.AssociatedRisk, m.ModuleName
FROM RiskTable r
FULL OUTER JOIN (
SELECT DISTINCT AssociatedRisk
FROM RiskTable
) as a on a.AssociatedRisk is not null
FULL OUTER JOIN (
SELECT DISTINCT ModuleName
FROM RiskTable
) as m on m.ModuleName is not null
WHERE MONTH(r.CreatedDate) between MONTH(@start_date) and MONTH(@end_date)
) as ac
LEFT JOIN RiskTable ri on ac.[month] = convert(varchar(7), ri.CreatedDate, 126)
and ac.AssociatedRisk = ri.AssociatedRisk
and ac.ModuleName = ri.ModuleName
GROUP BY ac.[month], ac.AssociatedRisk
ORDER BY ac.[month], ac.AssociatedRisk desc
END
ELSE
BEGIN
SELECT @model as [Module], ac.[Month], ac.AssociatedRisk as Risk, count(ri.ModuleName) as 'Total risks'
FROM (
SELECT DISTINCT convert(varchar(7), r.CreatedDate, 126) as [month], a.AssociatedRisk, m.ModuleName
FROM RiskTable r
FULL OUTER JOIN (
SELECT DISTINCT AssociatedRisk
FROM RiskTable
) as a on a.AssociatedRisk is not null
FULL OUTER JOIN (
SELECT DISTINCT ModuleName
FROM RiskTable
) as m on m.ModuleName = @model
WHERE r.CreatedDate between DATEADD(mm, DATEDIFF(mm, 0, @start_date), 0) and eomonth(@end_date)
) as ac
LEFT JOIN RiskTable ri on ac.[month] = convert(varchar(7), ri.CreatedDate, 126)
and ac.AssociatedRisk = ri.AssociatedRisk
and ac.ModuleName = ri.ModuleName
GROUP BY ac.ModuleName, ac.[month], ac.AssociatedRisk
ORDER BY ac.[month], ac.AssociatedRisk desc
END
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论