存储过程中的IF语句(总计noob)

时间:2019-05-24 21:51:38

标签: sql-server stored-procedures

背景:我有一个表,该表包含一个人的列表,另一个表用于发生的事件。我需要一个事件的发生日期,该事件最后发生在一个人的数据库列中。

所以我的理解是,我需要使用SQL Server代理创建并运行一个存储过程,该存储过程将为我执行此操作。不过,我从未编写过存储过程,因此这对我也是一种实践。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      Gary Senter
-- Create date: 5/25/2019
-- Description: Returns employee data.
-- =============================================
ALTER PROCEDURE [dbo].[spLocal_Safety_Sync] 
    @LastName NVARCHAR(50) = NULL, 
    @FirstName NVARCHAR(50) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @injury_date DATETIME;
    DECLARE @short_name_1 VARCHAR(50);
    DECLARE @short_name_2 VARCHAR(50);
    DECLARE @short_name_3 VARCHAR(50);
    DECLARE @cc_roster_id_emp_1 INT;
    DECLARE @cc_roster_id_emp_2 INT;
    DECLARE @cc_roster_id_emp_3 INT;

    SELECT 
        @short_name_1 = effected_employee_1,
        @short_name_2 =  effected_employee_2, 
        @short_name_3 = effected_employee_3,
        @injury_date = IncidentDate 
    FROM
        HSEBE.dbo.MCA_Data
    WHERE  
        (Classification = 'XX RI' OR Classification = 'YY RI')
    ORDER BY 
        IncidentDate ASC

    IF LEN(@short_name_1) > 0 
    THEN
        SELECT @cc_roster_id_emp_1 = autoid 
        FROM cc_rosters 
        WHERE short_name = @short_name_1

    IF LEN(@short_name_2) > 0 
    THEN
        SELECT @cc_roster_id_emp_2 = autoid 
        FROM cc_rosters 
        WHERE short_name = @short_name_2

    IF LEN(@short_name_3) > 0 
    THEN
        SELECT @cc_roster_id_emp_3 = autoid 
        FROM cc_rosters 
        WHERE short_name = @short_name_3

    IF @cc_roster_id_emp_1 > 0 
    THEN
        UPDATE cc_rosters 
        SET most_recent_injury = @injury_date 
        WHERE autoid = @short_name_1

    IF @cc_roster_id_emp_2 > 0 
    THEN
        UPDATE cc_rosters 
        SET most_recent_injury = @injury_date 
        WHERE autoid = @short_name_2

    IF @cc_roster_id_emp_3 > 0 
    THEN
        UPDATE cc_rosters 
        SET most_recent_injury = @injury_date 
        WHERE autoid = @short_name_3
END

我得到这些错误:

  

消息156,级别15,状态1,过程spLocal_Safety_Sync,第28行
  关键字“ THEN”附近的语法不正确。

     

消息156,级别15,状态1,过程spLocal_Safety_Sync,第30行
  关键字“ THEN”附近的语法不正确。

     

消息156,级别15,状态1,过程spLocal_Safety_Sync,第32行
  关键字“ THEN”附近的语法不正确。

     

消息156,级别15,状态1,过程spLocal_Safety_Sync,第35行
  关键字“ then”附近的语法错误。

     

消息156,级别15,状态1,过程spLocal_Safety_Sync,第37行
  关键字“ then”附近的语法错误。

     

消息156,级别15,状态1,过程spLocal_Safety_Sync,第39行
  关键字'then'附近的语法不正确。

不确定从何处转向。...

并不总是有effected_employee_1,2,3,有时选定的值不会从其他数据库返回。

1 个答案:

答案 0 :(得分:0)

好吧,这有点多了,我了解您仍在学习,所以让我向您展示我将如何处理。另外,将其与盐b / c混合使用,我对数据或预期的输出没有可见性。我认为,这将使您到达那里。但不利的是,它每次都会为每个员工更新。您可以更改以检查匹配项并轻松排除匹配项,但这比其他任何事情都更重要。

首先让我解释一下我在这里看到的问题:

  1. 看起来您的MCA_Data表中的数据结构错误。我的意思是说它是一个“扁平”表,其中有多名员工排成一排。通常,它是在多对一情况下执行检查数据任务时使用的PITA。通常,会有一个表,其中每个事件记录分别记录有事件ID和employeeID的每个人。我了解您可能没有构建它,但是值得为您指出自己的信息。

  2. 从根本上讲,一旦您理解了这个不那么理想的结构如何影响您的任务,这个问题就更容易解决。在我看来,这本质上是一个关键问题。 SQL中的PIVOT本质上是在切换行和列。如果要查找每个员工的最大事件发生日期,我们只需要更改MCA_Data表中的数据即可进行处理,对吗?有几种方法可以用代码来透视数据-选择您喜欢的-大多数人实际上都使用PIVOT函数,在这里我倾向于在CTE(常见表经验)和PIVOT之间摇摆不定。一旦了解IMO CTE,就更易于阅读。运行此代码,看看是否返回正确的结果。

       ; WITH CTE AS
       (
            SELECT Employee, AutoID, MAX(IncidentDate) AS MaxIncidentDate
            FROM
                (
                    SELECT 
                        effected_employee_1 AS Employee,
                        cc1.autoID AS AutoID,
                        MAX(IncidentDate) AS IncidentDate 
                    FROM 
                        HSEBE.dbo.MCA_Data mca
                    LEFT JOIN 
                        cc_rosters cc1 ON mac. effected_employee_1 = cc1. short_name
                    WHERE  
                        (Classification = 'XX RI' OR Classification = 'YY RI')
                        AND effected_employee_1 IS NOT NULL
                    GROUP BY 
                        effected_employee_1,
                        cc1.autoID
                    UNION
                    SELECT 
                        effected_employee_2 AS Employee,
                        cc2.AutoID  AS AutoID,
                        MAX(IncidentDate) AS IncidentDate 
                    FROM 
                        HSEBE.dbo.MCA_Data mca
                    LEFT JOIN 
                        cc_rosters cc2 ON mac. effected_employee_2 = cc2. short_name
                    WHERE  
                        (Classification = 'XX RI' OR Classification = 'YY RI')
                        AND effected_employee_2 IS NOT NULL 
                    GROUP BY 
                        effected_employee_2,
                        cc2.autoID                          
                    UNION
                    SELECT 
                        effected_employee_3 AS Employee, 
                        cc3.autoID AS AutoID,
                        MAX(IncidentDate) AS IncidentDate 
                    FROM 
                        HSEBE.dbo.MCA_Data mca
                    LEFT JOIN 
                        cc_rosters cc3 ON mac. effected_employee_3 = cc3. short_name
                    WHERE  
                        (Classification = 'XX RI' OR Classification = 'YY RI')
                        AND effected_employee_3 IS NOT NULL
                    GROUP BY 
                        effected_employee_3,
                        cc3.autoID      
                ) x
            GROUP BY 
                Employee, AutoID,
        )   
    SELECT * FROM CTE
    
    1. 现在,您为列中不为空的每个员工确定了最大事件发生日期之后,只需在此处进行更新即可。通过联接进行更新是您要擅长的事情。防止所有这些IF和变量以及各种语句。这也可以帮助您以基于集合的方式进行操作。在继续学习的过程中,您将不断听到。我建议您理解它!

      ; WITH CTE AS
      (
          SELECT Employee, AutoID, MAX(IncidentDate) AS MaxIncidentDate
          FROM
              (
                  SELECT 
                      effected_employee_1 AS Employee,
                      cc1.autoID AS AutoID,
                      MAX(IncidentDate) AS IncidentDate 
                  FROM 
                      HSEBE.dbo.MCA_Data mca
                  LEFT JOIN 
                      cc_rosters cc1 ON mac. effected_employee_1 = cc1. short_name
                  WHERE  
                      (Classification = 'XX RI' OR Classification = 'YY RI')
                      AND effected_employee_1 IS NOT NULL
                  GROUP BY 
                      effected_employee_1,
                      cc1.autoID
                  UNION
                  SELECT 
                      effected_employee_2 AS Employee,
                      cc2.AutoID  AS AutoID,
                      MAX(IncidentDate) AS IncidentDate 
                  FROM 
                      HSEBE.dbo.MCA_Data mca
                  LEFT JOIN 
                      cc_rosters cc2 ON mac. effected_employee_2 = cc2. short_name
                  WHERE  
                      (Classification = 'XX RI' OR Classification = 'YY RI')
                      AND effected_employee_2 IS NOT NULL 
                  GROUP BY 
                      effected_employee_2,
                      cc2.autoID                          
                  UNION
                  SELECT 
                      effected_employee_3 AS Employee, 
                      cc3.autoID AS AutoID,
                      MAX(IncidentDate) AS IncidentDate 
                  FROM 
                      HSEBE.dbo.MCA_Data mca
                  LEFT JOIN 
                      cc_rosters cc3 ON mac. effected_employee_3 = cc3. short_name
                  WHERE  
                      (Classification = 'XX RI' OR Classification = 'YY RI')
                      AND effected_employee_3 IS NOT NULL
                  GROUP BY 
                      effected_employee_3,
                      cc3.autoID      
              ) x
          GROUP BY 
              Employee, AutoID,
      )
      UPDATE r SET r.most_recent_injury = cte.MaxIncidentDate
      FROM cc_rosters r
      INNER JOIN CTE ON r.AutoID = CTE.AutoID AND r.short_name =cte.Employee;
      
    2. 在具有多个命令的过程中,习惯于使用';'。字符以终止每一行。这是一个好习惯。