光标中的转换错误?

时间:2016-11-20 23:28:30

标签: sql sql-server triggers cursor

运行简单的更新语句时,我一直收到此错误。

  

Msg 16922,Level 16,State 1,Procedure TRG_MEM_BALANCE_AWW,Line 72
  光标提取:不允许从数据类型datetime到decimal的隐式转换。

这是我的触发器代码。我没有看到错误转换的内容?

ALTER TRIGGER [dbo].[TRG_MEM_BALANCE_AWW]
ON [dbo].[DETAILRENTAL]
AFTER INSERT, DELETE, UPDATE
AS 
BEGIN
    IF(EXISTS(SELECT * FROM inserted) 
       AND
       EXISTS(SELECT * FROM deleted))
    BEGIN
        DECLARE CURSORFORUPDATE CURSOR FOR
            SELECT 
                I.RENT_NUM, I.DETAIL_DUEDATE, I.DETAIL_RETURNDATE, 
                I.DETAIL_DAILYLATEFEE, D.DETAIL_DUEDATE, 
                D.DETAIL_RETURNDATE, D.DETAIL_DAILYLATEFEE
            FROM 
                inserted I 
            INNER JOIN 
                DELETED D ON I.Rent_Num = D.Rent_Num 
                          AND I.Vid_Num = D.Vid_Num

        DECLARE @RENT_NUM INT
        DECLARE @RETURN_DATE_NEW DATETIME
        DECLARE @DUE_DATE_OLD DATETIME
        DECLARE @DUE_DATE_NEW DATETIME
        DECLARE @RETURN_DATE_OLD DATETIME
        DECLARE @DAILY_LATE_FEE_NEW DECIMAL(5,2)
        DECLARE @DAILY_LATE_FEE_OLD DECIMAL(5,2)
        DECLARE @LATE_FEE_PRIOR DECIMAL(5,2)
        DECLARE @LATE_FEE_AFTER DECIMAL(5,2)
        DECLARE @CHANGE DECIMAL (5,2)

        OPEN CURSORFORUPDATE 

        FETCH NEXT FROM CURSORFORUPDATE INTO @RENT_NUM, @DUE_DATE_NEW, @RETURN_DATE_NEW, @DAILY_LATE_FEE_NEW, @DUE_DATE_OLD, @RETURN_DATE_OLD, @DAILY_LATE_FEE_OLD

        WHILE (@@FETCH_STATUS = 0)
        BEGIN

--A
IF(@RETURN_DATE_OLD > @DUE_DATE_OLD)

BEGIN

    SELECT @LATE_FEE_PRIOR = DATEDIFF(DAY, @DUE_DATE_OLD, @RETURN_DATE_OLD) * @DAILY_LATE_FEE_OLD

    END
    ELSE
        SELECT @LATE_FEE_PRIOR = 0
--B
    IF(@RETURN_DATE_NEW > @DUE_DATE_NEW) 
    BEGIN
    SELECT @LATE_FEE_AFTER = DATEDIFF(DAY, @DUE_DATE_NEW, @RETURN_DATE_NEW) * @DAILY_LATE_FEE_NEW

    END
    ELSE
        SELECT @LATE_FEE_AFTER = 0

--C
    SELECT @CHANGE = @LATE_FEE_AFTER - @LATE_FEE_PRIOR

--D
    IF(@CHANGE <> 0)
    BEGIN
    DECLARE @MEM_NUM INT
    SELECT @MEM_NUM = M.Mem_Num
    FROM RENTAL R INNER JOIN MEMBERSHIP M ON R.MEM_NUM = M.MEM_NUM AND R.RENT_NUM = @RENT_NUM

    UPDATE MEMBERSHIP
    SET Mem_Balance = MEM_BALANCE + @CHANGE
    WHERE Mem_Num = @MEM_NUM 

    FETCH NEXT FROM CURSORFORUPDATE
    INTO @RENT_NUM, @DUE_DATE_NEW, @DUE_DATE_OLD, @RETURN_DATE_NEW, @RETURN_DATE_OLD, @DAILY_LATE_FEE_NEW, @DAILY_LATE_FEE_OLD

    END
    CLOSE CURSORFORUPDATE
    DEALLOCATE CURSORFORUPDATE

    END
END
END

我正在运行的更新

UPDATE DETAILRENTAL
SET DETAIL_RETURNDATE = 2013-03-10
WHERE RENT_NUM = 1001

这使得电影在DETAILRENTAL表中返回,这应该更新MEMBERSHIP表中的成员余额。任何有关如何解决此错误的想法都将不胜感激。

1 个答案:

答案 0 :(得分:0)

DETAIL_RETURNDATE字段可能有datetimedate类型,但您尝试将其设置为数字:2013-03-10 = 2013减3减10 = 2000 。

试试这个:

Update DETAILRENTAL
   Set DETAIL_RETURNDATE = Convert(datetime, '2013-03-10', 23)
   Where RENT_NUM = 1000;

在这种情况下,Convert(datetime, , 23)可能不是绝对必要的,但如果您的输入日期格式一致,这是很好的做法。

修改

前者可能是您问题的根源,但我也注意到这更可能是造成错误的原因

ALTER TRIGGER [dbo].[TRG_MEM_BALANCE_AWW]
ON [dbo].[DETAILRENTAL]
AFTER INSERT, DELETE, UPDATE
AS 
BEGIN
    IF (EXISTS (SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted))
    BEGIN
        DECLARE CURSORFORUPDATE CURSOR FOR
        SELECT I.RENT_NUM, I.DETAIL_DUEDATE, I.DETAIL_RETURNDATE,I.DETAIL_DAILYLATEFEE, 
            D.DETAIL_DUEDATE, D.DETAIL_RETURNDATE, D.DETAIL_DAILYLATEFEE
          FROM inserted I INNER JOIN DELETED D ON I.Rent_Num = D.Rent_Num AND I.Vid_Num = D.Vid_Num

        DECLARE @RENT_NUM INT
        DECLARE @RETURN_DATE_NEW DATETIME
        DECLARE @DUE_DATE_OLD DATETIME
        DECLARE @DUE_DATE_NEW DATETIME
        DECLARE @RETURN_DATE_OLD DATETIME
        DECLARE @DAILY_LATE_FEE_NEW DECIMAL(5,2)
        DECLARE @DAILY_LATE_FEE_OLD DECIMAL(5,2)
        DECLARE @LATE_FEE_PRIOR DECIMAL(5,2)
        DECLARE @LATE_FEE_AFTER DECIMAL(5,2)
        DECLARE @CHANGE DECIMAL (5,2)

        OPEN CURSORFORUPDATE 
        FETCH NEXT FROM CURSORFORUPDATE
        INTO @RENT_NUM, @DUE_DATE_NEW, @RETURN_DATE_NEW, @DAILY_LATE_FEE_NEW, 
                @DUE_DATE_OLD, @RETURN_DATE_OLD, @DAILY_LATE_FEE_OLD

        WHILE (@@FETCH_STATUS = 0)
        BEGIN
            --A
            IF(@RETURN_DATE_OLD > @DUE_DATE_OLD)
                SELECT @LATE_FEE_PRIOR = DATEDIFF(DAY, @DUE_DATE_OLD, @RETURN_DATE_OLD) * @DAILY_LATE_FEE_OLD;
            ELSE
                SELECT @LATE_FEE_PRIOR = 0;

            --B
            IF(@RETURN_DATE_NEW > @DUE_DATE_NEW) 
                SELECT @LATE_FEE_AFTER = DATEDIFF(DAY, @DUE_DATE_NEW, @RETURN_DATE_NEW) * @DAILY_LATE_FEE_NEW
            ELSE
                SELECT @LATE_FEE_AFTER = 0

            --C
            SELECT @CHANGE = @LATE_FEE_AFTER - @LATE_FEE_PRIOR

            --D
            IF(@CHANGE <> 0)
            BEGIN
                DECLARE @MEM_NUM INT;
                SELECT @MEM_NUM = M.Mem_Num
                  FROM RENTAL R 
                  INNER JOIN MEMBERSHIP M ON R.MEM_NUM = M.MEM_NUM AND R.RENT_NUM = @RENT_NUM

                UPDATE MEMBERSHIP
                   SET Mem_Balance = MEM_BALANCE + @CHANGE
                   WHERE Mem_Num = @MEM_NUM 
            END -- End of IF(@CHANGE <> 0)

            FETCH NEXT FROM CURSORFORUPDATE
            INTO @RENT_NUM, @DUE_DATE_NEW, @RETURN_DATE_NEW, @DAILY_LATE_FEE_NEW, 
                @DUE_DATE_OLD, @RETURN_DATE_OLD, @DAILY_LATE_FEE_OLD
        END  -- End of WHILE (@@FETCH_STATUS = 0)

        CLOSE CURSORFORUPDATE
        DEALLOCATE CURSORFORUPDATE
    END -- End of IF(EXISTS (Select * From Inserted) AND EXISTS (Select * From Deleted))
END -- end of trigger

似乎第二次从光标中取出时,列出的变量与第一次的顺序不同。因此,您尝试从DETAIL_DAILYLATEFEE插入@RETURN_DATE_NEWDETAIL_RETURNDATE插入@DAILY_LATE_FEE_NEW

我认为匹配BEGIN ... END可能也存在一些问题。

修改

这是我的测试脚本,似乎一切都在这里正常工作。

Create Table Rental (
    Rent_Num int,
    Mem_Num int);
Create Table DetailRental (
    Rent_Num int,
    Vid_Num int,
    Detail_DueDate datetime,
    Detail_ReturnDate datetime,
    Detail_DailyLateFee decimal(5,2));
Create Table Membership (
    Mem_Num int,
    Mem_Balance money);

Insert Into Membership Values (1, 0);
Insert Into Rental Values (1, 1);
Insert Into DetailRental 
Values  (1, 1, '2016-11-21', '2016-11-23', 1),
        (1, 2, '2015-11-21', '2016-11-22', 0.5);
Go

然后按照上一个列表

在表格上创建触发器
Select * From DetailRental;
Select * From Rental;
Select * From Membership;

Update DetailRental
   Set Detail_ReturnDate = '2016-11-21'
   Where Rent_Num = 1;

Select * From Membership;
Go

Mem_Num  Mem_Balance
1        0.00

Mem_Num  Mem_Balance
1        2.00