光标转换错误?
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
字段可能具有 datetime
或 date
类型,但您正在尝试将其设置为一个数字: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 嗨,我已经完整地复制了您的触发器定义以及建议的更改。你能试试这个新版本吗?以上是关于光标转换错误?的主要内容,如果未能解决你的问题,请参考以下文章