更新后触发 - 有条件的IF故障

时间:2015-03-05 01:44:50

标签: sql-server triggers

这里有一位SQL新手,正在寻求一些帮助。 我正在完成一个示例项目,我正在尝试解决以下用例,但我被卡住了。

客户取消其会员资格并且不会退回租借的DVD,因此需要向其帐户收取25美元的DVD更换费用。

涉及的表:Customer,Rented_out,Bill

基本上,我试图创建一个触发器而不是执行如果满足以下条件为了将条目插入到bill表中: 1.客户表中的Customer_status更新为“非活动” 2.在Rented_out表中,更新后的客户对date_returned块具有NULL值(表示未复制的DVD)。

以下是我写的内容,但是现在只要客户的状态发生变化(任何值),触发就会执行,而不是专门针对“非活动”,无论他们是否在日期的重定位块中都有NULL值。 rented_out表。我无法弄清楚如何应用这些限制。此外,客户可能有多个已租出的项目,因此输入到账单表中的25美元费用需要乘以该客户的rented_out表中的NULL值数。

我意识到你可能需要剩下的代码,所以如果是这样,请不要犹豫。

CREATE TRIGGER charge_for_unreturned_movie ON customer
AFTER UPDATE
AS
BEGIN customer
    DECLARE @customer_id INT;
    DECLARE @customer_status VARCHAR(20);
    DECLARE @bill_number INT;
    DECLARE @bill_amount_due DECIMAL(10,2);
    DECLARE @bill_payment_due_date DATE;
    SET @bill_number = ((SELECT MAX(bill_number) +1 FROM bill));
    SET @customer_id = (SELECT customer_id FROM inserted);
    SET @bill_amount_due = 25.00;
    SET @bill_payment_due_date = GETDATE()+30;
        IF UPDATE (customer_status)
            INSERT INTO bill(bill_number, customer_id, bill_amount_due, bill_payment_due_date)
            VALUES  (@bill_number, @customer_id, @bill_amount_due, @bill_payment_due_date)
            PRINT 'New charge added to customer account when status is changed to "Inactive"!';
END;

1 个答案:

答案 0 :(得分:0)

触发器可以做很酷的事情,但有些事情你需要注意。第一个也是最重要的:触发器对数据集进行操作,所以做SET @customer_id = (SELECT customer_id FROM inserted);这样的事情几乎肯定注定要失败,因为inserted表可以容纳多行(除非你只更新一个客户)一旦)。知道这一点很容易重写触发器以便设置识别。

注意:也许不应该检索和计算账单编号,而是在账单表中自动递增标识列?

我在代码中包含了一些注释,但它应该很容易理解。

CREATE TRIGGER charge_for_unreturned_movie ON customer
AFTER UPDATE
AS
BEGIN
    -- retrieve the max bill number, or 0 if there are no bills
    DECLARE @bill_number INT;
    SET @bill_number = (SELECT ISNULL(MAX(bill_number),0) FROM bill);

    DECLARE @bill_amount_due DECIMAL(10,2);
    SET @bill_amount_due = 25.00;

    DECLARE @bill_payment_due_date DATE;
    SET @bill_payment_due_date = GETDATE() + 30;

    -- if there has been an update
    IF UPDATE (customer_status)
    BEGIN    
       -- set up a table to hold the records that needs to be billed
       DECLARE @to_be_billed TABLE (
          bill_number int identity(1,1), 
          customer_id int, 
          unreturned int
       )

       -- fill the table with records where status has changed to 'Inactive'
       -- but disregard those who already were 'Inactive' (through the join 
       -- against the deleted table. Insert only those customers that have 
       -- unreturned items.
       -- Insert the customer_id and number of unreturned items.
       INSERT @to_be_billed (customer_id, unreturned) 
       SELECT i.customer_id, COUNT(*) 
       FROM inserted i 
       JOIN rented_out r ON i.customer_id = r.customer_id
       JOIN deleted d ON i.customer_id = d.customer_id 
       WHERE i.customer_status = 'Inactive' 
         AND r.date_returned IS NULL 
         AND d.customer_status <> 'Inactive'
       GROUP BY i.customer_id 
       HAVING COUNT(*) > 0
    END
    -- if the last insert had a @@rowcount over zero insert records into the bill table
    -- increment the bill_number using the identity column
    -- calculate the charge as count of unreturned items * @bill_amount_due
    IF(@@ROWCOUNT > 0)
     BEGIN
      INSERT INTO bill (bill_number, customer_id, bill_amount_due, bill_payment_due_date)
      SELECT @bill_number + bill_number, customer_id, unreturned * @bill_amount_due, @bill_payment_due_date 
      FROM @to_be_billed
      PRINT 'New charge added to customer account when status is changed to "Inactive"!';
     END
END;