SQL Server触发器错误消息

时间:2016-07-20 20:03:58

标签: sql-server triggers

这是我得到的错误:

  

Msg 512,Level 16,State 1,Procedure tr_UpdateFolio,Line 361
  子查询返回的值超过1。当子查询遵循=,!=,<,< =,>,> =或子查询用作表达式时,不允许这样做。

我现在一遍又一遍地使用这段代码几个小时。我没看到什么?任何帮助,将不胜感激。我已经在这几天工作了,这几乎是我需要工作以完成这个项目的一件事。

-- 2. Write a trigger named tr_UpdateFolio  that will be invoked when the Folio table 'status' 
-- field ONLY (column update) is changed.
ALTER TRIGGER tr_UpdateFolio ON FOLIO--switch alter back to create
AFTER UPDATE
AS
    IF UPDATE([Status])
    BEGIN
        DECLARE @Status char(1)
        DECLARE @FolioID smallint
        DECLARE @CheckinDate smalldatetime
        DECLARE @Nights tinyint
        DECLARE @CurrentDate smalldatetime = '7/27/2016 2:00:00 PM'

        SELECT 
            @Status = i.Status, 
            @FolioID = i.FolioID,  
            @CheckinDate = i.CheckinDate, 
            @Nights = i.Nights
        FROM 
            INSERTED i

        -- If Folio status is updated to 'C' for Checkout, trigger two different Insert statements to 
        -- (1) INSERT in the Billing table, the amount for the total lodging cost as BillingCategoryID1
        -- -  (normally the FolioRate * number of nights stay, but you must  also factor in any late checkout fees*). 
        -- *Checkout time is Noon on the checkout date. Guest is given a one hour 
        -- grace period to check out. After 1PM (but before 4PM), a 50% surcharge is added to the FolioRate. After 4PM, an 
        -- additional full night's FolioRate is applied. You can recycle code from A7  (part 5), but note it's not the exact same 
        -- function - we only need the late charge (if any).

        IF @Status = 'C'
           SET @Nights = 1

        --@CurrentDate may need to switch back to getdate()
        IF DATEDIFF(HOUR, @CheckinDate + @Nights, @CurrentDate) >= 16
            SET @Nights = @Nights + 1
        ELSE IF DATEDIFF(HOUR, @CheckinDate + @Nights, @CurrentDate) >= 13
            SET @Nights = @Nights + .5

        UPDATE FOLIO
        SET Nights = @Nights
        WHERE FolioID = @FolioID

        INSERT INTO BILLING (FolioID, BillingCategoryID, BillingDescription, BillingAmount, BillingItemQty, BillingItemDate)
        VALUES (25, 1, 'Room', dbo.GetRackRate(11, @CurrentDate) * @Nights, 1, @CurrentDate)

        -- (2) The second INSERT statement in the same trigger will insert the Lodging Tax* - as a separate entry in the 
        -- Billing table for tax on lodging (BillingCategoryID2).  *Use the dbo.GetRoomTaxRate function from A7 to determine 
        -- the Lodging Tax.  
        INSERT INTO BILLING (FolioID, BillingCategoryID, BillingDescription, BillingAmount, BillingItemQty, BillingItemDate)
        VALUES (25, 2, 'Lodging Tax', dbo.GetRoomTaxRate(20), 1, @CurrentDate)
END
GO

-- 3. Write a trigger named tr_GenerateBill that will be invoked when an entry is INSERTED in to the Billing 
-- table. If BillngCategoryID is 2 (for testing purposes only) then call the function dbo.ProduceBill (from A7).

ALTER TRIGGER tr_GenerateBill ON BILLING
AFTER INSERT
AS
BEGIN
DECLARE @FolioID smallint
DECLARE @BillingCategoryID smallint

SELECT @FolioID = i.FolioID, @BillingCategoryID = i.BillingCategoryID
FROM INSERTED i

IF @BillingCategoryID = 2
SELECT * FROM dbo.ProduceBill(@FolioID)
END
GO

dbo.producebill应该没问题,但是当我尝试运行此块

时会发生错误
-- 4A. Assume today is (July 27, 2016 at 2PM)*. Anita is due to check out today (from Part 1 above).
-- Write an Update Statement to change the status of her Folio to 'CheckedOut.
-- (Be careful to include a WHERE clause so ONLY here folio is updated).
-- Note: This should automatically invoke tr_UpdateFolio above (factoring in the late charge),
-- which automatically invokes tr_GenerateBill  above, and calls dbo.ProduceBill , and produces a bill.

UPDATE FOLIO
SET [Status] = 'C'
WHERE ReservationID = 5020

我很想解决这个问题。感谢。

1 个答案:

答案 0 :(得分:0)

让我们从更简单的一个开始(tr_GenerateBill)。这个有点奇怪。您在插入触发器中有一个select语句。这意味着当您插入一行时,您希望它返回行。这不是插入的典型行为,但您可以使用它。

如果您插入3行,其中只有2行的BillingCategoryID为2,触发器应该做什么?该表的值函数是什么样的?

这是一种猜测,但你应该能够将整个触发器重写为这些内容。

ALTER TRIGGER tr_GenerateBill ON BILLING
AFTER INSERT
AS
BEGIN
    SELECT * 
    FROM inserted i
    cross apply dbo.ProduceBill(i.FolioID) pb
    where i.BillingCategoryID = 2
END

你的第二次触发更具挑战性。你在这里尝试做什么并不完全清楚,但我认为这非常接近。

UPDATE f
set Nights = case when DATEDIFF(HOUR, @CheckinDate + i.Nights, @CurrentDate) >= 16 then 2 else 1 end --adding .5 to a tiny int is pointless. It will ALWAYS be the same value.
from inserted i
join Folio f on f.FolioID = i.FolioID


INSERT INTO BILLING (FolioID, BillingCategoryID, BillingDescription, BillingAmount, BillingItemQty, BillingItemDate)
Select i.FolioID
    , 1
    , 'Room'
    , dbo.GetRackRate(11, @CurrentDate) * case when DATEDIFF(HOUR, @CheckinDate + i.Nights, @CurrentDate) >= 16 then 2 else 1 end, 1, @CurrentDate)
from inserted i

INSERT INTO BILLING (FolioID, BillingCategoryID, BillingDescription, BillingAmount, BillingItemQty, BillingItemDate)
select i.FolioID
    , 2
    , 'Lodging Tax'
    , dbo.GetRoomTaxRate(20), 1, @CurrentDate)
from inserted i