2016-07-20 4 views
0

この私が取得していますエラーです:SQL Serverのトリガーエラーメッセージ

をメッセージ512、レベル16、状態1、プロシージャtr_UpdateFolio、ライン361
サブクエリは複数の値を返しました。 =、!=、<、< =、>、> =、またはサブクエリが式として使用されている場合は、これは許可されません。

私は今このコードを何時間も繰り返し実行してきました。私は何を見ていないのですか?どんな助けもありがとう。私は数日間この作業に取り組んできましたが、これはこのプロジェクトを完了させるために必要な作業です。

-- 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 

     [email protected] 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

トリガーには大きな欠陥があります。一度に1つの行だけが挿入されると仮定しています。これは、SQL Serverでトリガーが動作する方法ではありません。 1回の操作ではなく、1回の操作で1回発射されます。あなたはこれに基づいてロジックを設定する必要があります。これらのスカラー関数を取り除くことを検討するかもしれません、彼らは悪名高い貧しいパフォーマーです。 –

+0

私はこれを修正する必要があるとは思わない。私はちょうどトリガーを学んでいるので、それはこれになるとまだ少し不安です。 – Godfried23

+1

ENTIREトリガーは、どちらも単一の行の概念に基づいて設計されています。それらは両方ともセットを扱うために完全に再構築する必要があります。 –

答えて

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 

第2のトリガーはより困難です。ここで何をしようとしているのかははっきりしていませんが、これはかなり近いと思います。

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 
+0

2回目のトリガーで、私は50%の追加料金を追加しようとしています。 IF @Status = 'C'の直前のコメントは、何が起こる必要があるかを説明しています。 – Godfried23

+0

私はこれらの変更を加えましたが、私はまだ同じエラーが発生しています。 – Godfried23

+0

私はこの2時間の間これを戦ってきました。私は何を見ていないのですか? – Godfried23