【问题标题】:How do i create a stored procedure that checks a status, validates, then update status?如何创建一个检查状态、验证然后更新状态的存储过程?
【发布时间】:2020-12-27 04:12:43
【问题描述】:

我有以下“握手”表:

CREATE TABLE [dbo].[Handshake]
(
    [Report Year] [varchar](100) NULL,
    [Status] [varchar](100) NULL,
    [Update Time] [datetime] NULL,
    [Process Time] [datetime] NULL
) ON [PRIMARY]
GO

这里有一些数据:

Report Year Status  Update Time             Process Time
--------------------------------------------------------
2020 1+2    Loaded  2020-08-25 13:10:19.073 NULL
2020 6+8    Loaded  2020-08-25 13:11:30.733 NULL
2020 1+2    Loaded  2020-08-25 13:11:47.257 NULL

我有另一个表,“事实”,用于每次插入上述“报告年”的负载,并且当后端进程开始加载/更新状态时,将一条记录插入到握手表中加载完成后从“WIP”变为“Loaded”,从上面的示例握手数据中可以看出。

状态为Loaded后,我每次都手动进入,对Fact表运行以下查询,以验证其他表的数据。

SELECT COUNT(*) AS 'Report Year Count' 
FROM Fact 
WHERE [Report Year] NOT IN (SELECT DISTINCT [Report Year] FROM [Report Year])

SELECT COUNT(*) AS 'COS Count' 
FROM Fact 
WHERE [Country Code] NOT IN (SELECT DISTINCT [Country Code] FROM [COS])

SELECT COUNT(*) AS 'Franchise Count' 
FROM Fact 
WHERE [Style Code] NOT IN (SELECT DISTINCT [Style Code] FROM [Franchise])

SELECT COUNT(*) AS 'Product Count' 
FROM Fact 
WHERE [Style Code] NOT IN (SELECT DISTINCT [Style Code] FROM [Product])
  • 如果上述查询的计数为 0,那么我不会检查这些表的拒绝数。
  • 如果计数 > 0,我会运行类似的查询来识别拒绝。

例如,如果 Franchise 和 Product 返回计数 1063,

然后我运行以下相关查询来识别这些表中缺少的拒绝:

SELECT DISTINCT [Style Code] AS 'Franchise - Style Code' 
FROM Fact 
WHERE [Style Code] NOT IN (SELECT DISTINCT [Style Code] FROM [Franchise])

SELECT DISTINCT [Style Code] AS 'Product - Style Code' 
FROM Fact 
WHERE [Style Code] NOT IN (SELECT DISTINCT [Style Code] FROM [Product])

如果有“拒绝”(不一致的数据),我会向相关用户发送一封电子邮件,说明拒绝的位置,以便他们可以更新表格(即特许经营、COS、产品、报告年份)以包括之前丢失的拒绝我继续下一步(处理数据库)。

我想编写一个存储过程,而不是手动执行此验证任务,该存储过程将由某种形式的脚本/作业(目前与此线程的范围无关)触发,它将检查握手表最新的“已加载”状态,运行验证查询,如果有拒绝,则从“已加载”->“拒绝”更新握手表中该记录的状态。否则,如果没有拒绝,则将状态更新为“良好”以表示没有发现拒绝。

如果有拒绝,我想将结果保存到标量变量(即 cmd)中,以便稍后将它们提取到各种 csv 文件中

这是我的伪代码:

Create PROCEDURE [dbo].[CheckRejects] AS
    DECLARE @cmd NVARCHAR(1000)
BEGIN
    --check Handshake Status. 
    IF Status='Loaded' THEN --RUN Validation Queries
        SELECT COUNT(*) as 'Report Year Count' FROM Fact WHERE [Report Year] NOT IN ( SELECT DISTINCT [Report Year] FROM [Report Year] )
        SELECT COUNT(*) as 'COS Count' FROM Fact WHERE [Country Code] NOT IN ( SELECT DISTINCT [Country Code] FROM [COS] )
        SELECT COUNT(*) as 'Franchise Count' FROM Fact WHERE [Style Code] NOT IN ( SELECT DISTINCT [Style Code] FROM [Franchise] )
        SELECT COUNT(*) as 'Product Count' FROM Fact WHERE [Style Code] NOT IN ( SELECT DISTINCT [Style Code] FROM [Product] )
        
        case 
            when 'Report Year Count' > 0 THEN
                SET Status='Rejects'
                SET @cmd = SELECT DISTINCT [Report Year] as 'Report Year' FROM Fact WHERE [Report Year] NOT IN ( SELECT DISTINCT [Report Year] FROM [Report Year] )
            when 'COS Count' > 0 THEN 
                SET Status='Rejects'
                SET @cmd = SELECT DISTINCT [Country Code] as 'COS - Country Code' FROM Fact WHERE [Country Code] NOT IN ( SELECT DISTINCT [Country Code] FROM [COS] )
            when 'Franchise Count' > 0 THEN
                SET Status='Rejects'
                SET @cmd = SELECT DISTINCT [Style Code] as 'Franchise - Style Code' FROM Fact WHERE [Style Code] NOT IN ( SELECT DISTINCT [Style Code] FROM [Franchise] )
            when 'Product Count' > 0 THEN
                SET Status='Rejects'
                SET @cmd = SELECT DISTINCT [Style Code] as 'Product - Style Code' FROM Fact WHERE [Style Code] NOT IN ( SELECT DISTINCT [Style Code] FROM [Product] )
            ELSE SET Status='Good' -- No Rejects, continue to processing DB
END
SELECT @cmd As Rejects 

【问题讨论】:

  • 那么你的问题是什么?你似乎有一个目标——你尝试了什么,你发现了什么问题需要帮助? SO 不是免费的代码编写服务。我建议您将目标分解为可以解决的部分,而不是一次完成所有事情-简单的分而治之就是您已经编写了一些查询。只需将逻辑拼接在一起即可运行它们并根据结果采取行动。
  • @SMor 我的目标是创建一个像我上面那样的 SP。我已经尝试过上述 SP,但它会导致错误。需要帮助以更好地正确运行
  • @SM我刚刚意识到最后一句话在我的帖子中被截断了。我已经用确切需要的内容更新了我的帖子

标签: sql-server


【解决方案1】:

我无权访问您的数据/架构,因此这是未经测试的尝试,但您可以尝试以下操作:

DECLARE
    @ValidationStatus VARCHAR(10),
    @ReportYearCmd VARCHAR(1000),
    @CosCountCmd VARCHAR(1000),
    @FranchiseCountCmd AS VARCHAR(1000),
    @ProductCountCmd AS VARCHAR(1000);

SET NOCOUNT ON;

-- Handshake Validations --
SELECT TOP 1
    @ReportYearCmd = CASE WHEN Report_Year_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Report Year] AS [Report Year] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Report Year] WHERE [Report Year].[Report Year] = [Fact].[Report Year] );'
    END,
    @CosCountCmd = CASE WHEN COS_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Country Code] AS [COS - Country Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [COS] WHERE [COS].[Country Code] = [Fact].[Country Code] );' 
    END,
    @FranchiseCountCmd = CASE WHEN  Franchise_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Style Code] AS [Franchise - Style Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Franchise] WHERE [Franchise].[Style Code] = [Fact].[Style Code] );' 
    END,
    @ProductCountCmd = CASE WHEN Product_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Style Code] AS [Product - Style Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Product] WHERE [Product].[Style Code] = [Fact].[Style Code] );' 
    END,
    @ValidationStatus = CASE
        WHEN ( Report_Year_Count = 0 AND COS_Count = 0 AND Franchise_Count = 0 AND Product_Count = 0 ) THEN 'Good'
        ELSE 'Rejects'
    END
FROM [Handshake] 
OUTER APPLY (

    SELECT 
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Report Year] WHERE [Report Year].[Report Year] = [Fact].[Report Year] ) ), 0 ) AS [Report_Year_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [COS] WHERE [COS].[Country Code] = [Fact].[Country Code] ) ), 0 ) AS [COS_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Franchise] WHERE [Franchise].[Style Code] = [Fact].[Style Code] ) ), 0 ) AS [Franchise_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Product] WHERE [Product].[Style Code] = [Fact].[Style Code] ) ), 0 ) AS [Product_Count]

) AS [ValidationCounts]
WHERE 
    [Handshake].[Status] = 'Loaded'
ORDER BY
    [Handshake].[Update Time] DESC;
        
-- Return validation results --

SELECT
    ISNULL( @ValidationStatus, 'Good' ) AS ValidationStatus,
    @ReportYearCmd AS ReportYearCmd,
    @CosCountCmd AS CosCountCmd,
    @FranchiseCountCmd AS FranchiseCountCmd,
    @ProductCountCmd AS ProductCountCmd;

更新:

如果我想在存储过程中使用 ValidationStatus 更新握手表,我可以在哪里执行此操作?

尝试以下方法:

DECLARE
    @ReportYearCmd VARCHAR(1000),
    @CosCountCmd VARCHAR(1000),
    @FranchiseCountCmd AS VARCHAR(1000),
    @ProductCountCmd AS VARCHAR(1000);

WITH Validations AS (
    SELECT TOP 1 * FROM [Handshake] WHERE [Status] = 'Loaded' AND [Update Time] = ( SELECT MAX( [Update Time] ) FROM Handshake )
)
UPDATE Validations 
SET 
    @ReportYearCmd = CASE WHEN Report_Year_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Report Year] AS [Report Year] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Report Year] WHERE [Report Year].[Report Year] = [Fact].[Report Year] );'
    END,
    @CosCountCmd = CASE WHEN COS_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Country Code] AS [COS - Country Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [COS] WHERE [COS].[Country Code] = [Fact].[Country Code] );' 
    END,
    @FranchiseCountCmd = CASE WHEN  Franchise_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Style Code] AS [Franchise - Style Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Franchise] WHERE [Franchise].[Style Code] = [Fact].[Style Code] );' 
    END,
    @ProductCountCmd = CASE WHEN Product_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Style Code] AS [Product - Style Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Product] WHERE [Product].[Style Code] = [Fact].[Style Code] );' 
    END,
    [Status] = CASE
        WHEN ( Report_Year_Count = 0 AND COS_Count = 0 AND Franchise_Count = 0 AND Product_Count = 0 ) THEN 'Good'
        ELSE 'Rejects'
    END
FROM [Validations] 
OUTER APPLY (

    SELECT 
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Report Year] WHERE [Report Year].[Report Year] = [Fact].[Report Year] ) ), 0 ) AS [Report_Year_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [COS] WHERE [COS].[Country Code] = [Fact].[Country Code] ) ), 0 ) AS [COS_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Franchise] WHERE [Franchise].[Style Code] = [Fact].[Style Code] ) ), 0 ) AS [Franchise_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Product] WHERE [Product].[Style Code] = [Fact].[Style Code] ) ), 0 ) AS [Product_Count]

) AS [ValidationCounts];

-- Return validation results --

SELECT
    @ReportYearCmd AS ReportYearCmd,
    @CosCountCmd AS CosCountCmd,
    @FranchiseCountCmd AS FranchiseCountCmd,
    @ProductCountCmd AS ProductCountCmd;

-- Optionally email the dynamic statements to someone --

IF @ReportYearCmd IS NOT NULL
    EXEC msdb..sp_send_dbmail 
        @profile_name = 'your_dbmail_profile',
        @recipients = 'email@domain.com',
        @subject = 'ReportYear Load Rejects',
        @execute_query_database = 'your_db_name',
        @query = @ReportYearCmd,
        @query_result_header = 0,
        @query_attachment_filename = 'ReportYearRejects.csv',
        @attach_query_result_as_file = 1,
        @query_result_separator = ';',
        @exclude_query_output = 1,
        @query_result_no_padding = 1;

IF @CosCountCmd IS NOT NULL
    EXEC msdb..sp_send_dbmail 
        @profile_name = 'your_dbmail_profile',
        @recipients = 'email@domain.com',
        @subject = 'COS Load Rejects',
        @execute_query_database = 'your_db_name',
        @query = @CosCountCmd,
        @query_result_header = 0,
        @query_attachment_filename = 'COSRejects.csv',
        @attach_query_result_as_file = 1,
        @query_result_separator = ';',
        @exclude_query_output = 1,
        @query_result_no_padding = 1;

IF @FranchiseCountCmd IS NOT NULL
    EXEC msdb..sp_send_dbmail 
        @profile_name = 'your_dbmail_profile',
        @recipients = 'email@domain.com',
        @subject = 'Franchise Load Rejects',
        @execute_query_database = 'your_db_name',
        @query = @FranchiseCountCmd,
        @query_result_header = 0,
        @query_attachment_filename = 'FranchiseRejects.csv',
        @attach_query_result_as_file = 1,
        @query_result_separator = ';',
        @exclude_query_output = 1,
        @query_result_no_padding = 1;

IF @ProductCountCmd IS NOT NULL
    EXEC msdb..sp_send_dbmail 
        @profile_name = 'your_dbmail_profile',
        @recipients = 'email@domain.com',
        @subject = 'Product Load Rejects',
        @execute_query_database = 'your_db_name',
        @query = @ProductCountCmd,
        @query_result_header = 0,
        @query_attachment_filename = 'ProductRejects.csv',
        @attach_query_result_as_file = 1,
        @query_result_separator = ';',
        @exclude_query_output = 1,
        @query_result_no_padding = 1;

【讨论】:

  • 哦,这太棒了!顺便说一句,存储过程可以简单地检查最新(最近的)更新时间,而不是在AND [Handshake].[Report Year] = '2020 1+2'; 检查特定的报告年份吗?是AND MAX [Handshake].[Update Time]吗?
  • @Cataster Handshake 是否有一个身份列或可以排序以执行TOP 1 的最新记录?
  • 不,它不是:/ 除了可能是更新时间之外,这里没有任何东西真正算得上是唯一的,但即使那是一个不确定的列。我在想在存储过程中可以有一个查询,按 DESC 对更新时间进行排序并以这种方式选择前 1 个
  • 没有 ID 也是我的方法。
  • @Cataster 我已将我的示例修改为TOP 1,并使用[Handshake.][Update Time] DESC 排序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多