使用存储过程的薪水 PAYE 括号

Salary PAYE brackets using a stored procedure

我正在尝试插入 Employee table,我希望 if 语句插入 SalaryNetSalaryDeduction如果 Employee 将根据小时费率赚取一定数量的列。

如果语句是为了在金额落入特定括号时将数据插入相关列

ALTER PROCEDURE [dbo].[spSaveEmployee]
    (@EmployeePersonName Varchar(20),
     @JobTitle int,
     @Branch int,
     @Department int,
     @Manager int,
     @HourlyRate MONEY,
     @PaymentDate datetime = '2021-10-05 00:00:00.000',
     @ErrorMessage Varchar(50) OUTPUT)
AS 
BEGIN
    DECLARE @DefaultDate DATETIME = GETDATE()

    --DECLARE @PAYE INT 
    --SET @PAYE = 26 / 100

    DECLARE @Salary INT
    --SET @Salary = @HourlyRate * 180
   
    --DECLARE @PYE INT
    --SET @PYE = 1.15
    DECLARE @NetSalary MONEY
    DECLARE @Deduction DECIMAL (18,2)

    DECLARE @NetSalary1 MONEY
    DECLARE @NetSalary2 MONEY
    DECLARE @NetSalary3 MONEY

    --SET @NetSalary = @Salary - @PYE

    DECLARE @Deduction1 DECIMAL (18,2)
    DECLARE @Deduction2 DECIMAL (18,2)
    DECLARE @Deduction3 DECIMAL (18,2)

    SET @Deduction1 = (@Salary * 18) / 100
    SET @NetSalary1 =  @Salary - @Deduction1
  
    SET @Deduction2 = (@Salary * 26) / 100
    SET @NetSalary2 =  @Salary - @Deduction2

    SET @Deduction3 = (@Salary * 31) / 100
    SET @NetSalary3 =  @Salary - @Deduction3

    IF NOT EXISTS (SELECT * FROM EmployeeBook 
                   WHERE EmployeePersonName = @EmployeePersonName)
    BEGIN
        INSERT INTO EmployeeBook (EmployeePersonName, JobTitle, Branch, Department, 
                                  Manager, HourlyRate, PAYE_Tax, Salary, 
                                  NetSalary, PaymentDate, Deductions)
        VALUES (@EmployeePersonName, @JobTitle, @Branch, @Department,
                @Manager, @HourlyRate, 1.15, @Salary,
                @NetSalary, @DefaultDate, @Deduction)

        SET @ErrorMessage = ''
        
        IF @Salary <= 321000
        BEGIN
            SELECT @Deduction = @Deduction
            SELECT @NetSalary = @NetSalary
        END 
        ELSE IF @Salary >= 321001 AND @Salary <= 445100
        BEGIN
            SELECT @Deduction = @Deduction2
            SELECT @NetSalary =  @NetSalary2
        END 
        ELSE IF @Salary >= 445100 AND @Salary <= 584200
        BEGIN
            SELECT @Deduction = @Deduction3
            SELECT @NetSalary = @NetSalary3 
        END
    END 
    ELSE
    BEGIN
        SET @EmployeePersonName = '' 
        SET @JobTitle = 0 
        SET @Branch = 0
        SET @Department = 0
        SET @Manager = 0
        SET @HourlyRate = 0.00
        SET @Salary = 0.00
        SET @NetSalary = 0.00
        SET @PaymentDate = @DefaultDate
        SET @Deduction = 0

        SET @ErrorMessage = 'Sorry could not save ' + @EmployeePersonName + ' Employee name already exists'
    END
END
GO

以下是我认为您正在努力完成的工作。问题和评论:

  1. 您在使用变量后对其进行设置 - 因此它们无效。
  2. T-SQL 针对基于集合的操作进行了优化,因此您应该尽可能尝试以基于集合的方式执行操作,而不是程序性的
  3. 最佳做法是为 T-SQL
  4. 使用一致的大小写
  5. 正如 Larnu 指出的那样,错误处理最好使用 throw 来处理。
  6. 最佳做法是始终为数据库对象添加架构前缀
  7. SP 应始终有一个 return 声明
  8. SP 应该正常启动 SET NOCOUNT, XACT_ABORT ON;
  9. 既然你可以立即验证此人的存在,我会节省任何进一步的处理时间。
  10. 如果薪水超出定义的范围怎么办?您可能不期望它,但您应该处理它,因此 CASE 表达式中的 ELSE
  11. 我会避免在您的 SP 前加上 sp 前缀,因为它太接近系统前缀 sp_。事实上,为什么要给它们加上前缀?
  12. 像这样创建括号时,一个结束条件需要是 less than or equal,另一个条件是 greater than(反之亦然),以避免值落入 2 个括号中。尽管case会短路到第一个匹配的表达式,但从理解的角度来看,最好有正确和准确的逻辑。
ALTER PROCEDURE [dbo].[SaveEmployee]
(
    @EmployeePersonName VARCHAR(20),
    @JobTitle INT,
    @Branch INT,
    @Department INT,
    @Manager INT,
    @HourlyRate MONEY,
    @PaymentDate DATETIME = '2021-10-05 00:00:00.000',
    @ErrorMessage VARCHAR(50) OUTPUT
)
AS 
BEGIN
    SET NOCOUNT, XACT_ABORT ON;

    IF EXISTS (SELECT 1 FROM dbo.EmployeeBook WHERE EmployeePersonName = @EmployeePersonName) BEGIN
        SET @ErrorMessage = 'Sorry could not save ' + @EmployeePersonName + ' Employee name already exists' END
        RETURN;
        -- Comment out 2 lines above to uncomment the 2 code line below
        -- As suggested by Larnu, this would be more a typical error handling approach
        --DECLARE @Error NVARCHAR(2048) = 'Sorry could not save ' + @EmployeePersonName + ' Employee name already exists';
        --THROW 51000, @Error, 1;
    END;

    DECLARE @DefaultDate DATETIME = GETDATE(), @Salary INT = @HourlyRate * 180;

    INSERT INTO dbo.EmployeeBook (EmployeePersonName, JobTitle, Branch, Department 
        , Manager, HourlyRate, PAYE_Tax, Salary 
        , NetSalary, PaymentDate, Deductions)
    SELECT EmployeePersonName, JobTitle, Branch, Department
        , Manager, HourlyRate, 1.15, Salary
        , CASE SalaryBracket WHEN 1 THEN Salary - Deduction1
          WHEN 2 THEN Salary - Deduction2
          WHEN 3 THEN Salary - Deduction3
          -- ELSE ??
          END
        , @DefaultDate
        , CASE SalaryBracket WHEN 1 THEN Deduction1
          WHEN 2 THEN Deduction2
          WHEN 3 THEN Deduction3
          -- ELSE ??
          END
    FROM (
        VALUES (@EmployeePersonName, @JobTitle, @Branch, @Department, @Manager, @HourlyRate, 1.15, @Salary
          , (@Salary * 18) / 100, (@Salary * 26) / 100, (@Salary * 31) / 100
          -- Compute Salary Bracket in one place for reuse
          , CASE WHEN @Salary <= 321000 THEN 1
            WHEN @Salary > 321001 AND @Salary <= 445100 THEN 2
            WHEN @Salary > 445100 AND @Salary <= 584200 THEN 3 END
          )
    ) AS X (EmployeePersonName, JobTitle, Branch, Department, Manager, HourlyRate, PAYE_Tax, Salary, Deduction1, Deduction2, Deduction3, SalaryBracket);

    RETURN 0;
END
GO