光标转换错误?

Posted

技术标签:

【中文标题】光标转换错误?【英文标题】:Conversion error in cursor? 【发布时间】:2016-11-20 23:28:29 【问题描述】:

当我运行一个简单的更新语句时,我不断收到这个错误。

消息 16922,级别 16,状态 1,过程 TRG_MEM_BALANCE_AWW,第 72 行 游标提取:不允许从数据类型 datetime 到十进制的隐式转换。

这是我的触发器代码。我没有看到什么转换不正确?

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 表中的成员余额。任何有关如何解决此错误的想法将不胜感激。

【问题讨论】:

我添加了数据库标签。语法显然是 SQL Server。 【参考方案1】:

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_NEW 和从DETAIL_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

【讨论】:

感谢您的回复。我先做了不同的更新语句样式,但它不起作用。然后我更改了 fetch 语句中变量的顺序以相互匹配,并再次尝试更新语句,但它仍然不起作用。我收到此错误:“从字符串转换日期和/或时间时转换失败”。当我以原始方式尝试更新语句时,我收到一条错误消息,提示“不存在名为“CURSORFORUPDATE”的游标。我不明白如果它从光标中拉出光标的名称,它怎么说它不存在? @AustinWeller 我们可以继续聊天吗:chat.stackexchange.com/rooms/48862/… 我不会反对,但我在这个网站上的声誉还不够高,显然不能聊天 @AustinWeller 哦,所以当您更改 FETCH NEXT 中变量的顺序时,您将它们按以下顺序排列:@RENT_NUM, @DUE_DATE_NEW, @RETURN_DATE_NEW, @DAILY_LATE_FEE_NEW, @DUE_DATE_OLD, @RETURN_DATE_OLD, @DAILY_LATE_FEE_OLD? @AustinWeller 嗨,我已经完整地复制了您的触发器定义以及建议的更改。你能试试这个新版本吗?

以上是关于光标转换错误?的主要内容,如果未能解决你的问题,请参考以下文章

我的带有光标的购物车程序正在抛出错误

此方法的光标

vi命令-模式转换

Android 光标错误 - 确保光标已正确初始化

如何在python中将光标列表转换为JSON格式?

将pymongo光标转换为json