【问题标题】:SQL stored procedure error about int while there is no int没有 int 时有关 int 的 SQL 存储过程错误
【发布时间】:2019-10-01 21:04:43
【问题描述】:

在我的存储过程(插入存储过程)中,我有一个部分用于检查客户是否存在。当我给一个存在的客户名称(varchar)时,没有错误,但是当我插入一个不存在的名称时,它给了我这个错误:

转换 varchar 值“Briggs Standih”时转换失败 数据类型为 int。

Briggs Standih 在我的数据库中是一个不存在的客户。

我不知道错误可能出在哪里...这是我的程序和可执行文件。

create PROCEDURE spNieuweReservering
( 
   @customer VARCHAR(255), 
   @date1 date,
   @date 2date,
   @hotel varchar(40),
   @count_person int ,
   @emplyeeidint,
   @roomidint

) 
AS 
BEGIN 
   DECLARE @bookdate date    
IF not exists (
   SELECT count(*)
   FROM customer
   WHERE @customer= name
   )   
   BEGIN 
    raiserror('Deze klant bestaat niet. Controleer de naam of maak een nieuwe klant aan.',16,1)
   END 

   select @customer= customerid
   from customer
   where @customer= name

   select @hotel = hotelid
   from hotel
   where @hotel = location

   SELECT @bookdate= GETDATE()
   FROM boeking 

   begin transaction
   INSERT INTO booking values (@bookdate, @count_person, null, @customer, @hotel, @employeeid)
   insert into roombooking values (@roomid, @date1, @date2, null, null)
IF @@ERROR <> 0
BEGIN
    rollback
    raiserror('Er is een fout opgetreden bij het toevoegen van de reservering. Controleer de input',16,1)
    return
END
END 
commit

exec spNieuweReservering 'Briggs Standih', '2019-08-10', '2019-08-15', 'Eindhoven', 1, 1, 1

希望有人知道我做错了什么。

【问题讨论】:

  • 程序的哪一行导致错误?如果这些行是错误发生的地方,请您向我们展示您的预订和房间预订表的架构
  • 这是哪个 dbms?
  • SELECT @bookdate= GETDATE() FROM boeking?对于每一行? declare @BookDate as Date = GetDate(); 怎么样?

标签: sql sql-server tsql stored-procedures types


【解决方案1】:
  select @customer= customerid
  from customer
  where @customer= name

这是您尝试将 int 放入 @customer varchar 的错误。 酒店也会出现同样的错误

select @hotel = hotelid
from hotel
where @hotel = location

我建议声明 2 个其他变量

DECLARE @hotelId, @customerId INT

并使用这些来实现您的结果

【讨论】:

  • 错误是关于尝试将 varchar 放入 int,而不是相反。将 int 放入 varchar 不会导致问题
【解决方案2】:

代码出现错误的原因是您用于检查现有客户的代码存在逻辑问题。您试图询问是否存在包含该客户姓名的行。但是,因为您使用了COUNT(),所以您实际上要问的是是否有一行包含具有该名称的客户数量的计数。即使计数为 0,也总会有一行,所以EXISTS 永远为真。

IF not exists (
   SELECT name
   FROM customer
   WHERE @customer= name

将通过尝试选择字段而不是使用聚合函数来解决此问题。


除此之外,错误本身源于一些糟糕的编程实践。具体来说,我说的是使用同一个变量来存储两条不同的信息,而不是使用正确的数据类型来存储信息。

您已经这样做了两次,@customer@hotel 都开始表示名称,但您稍后尝试重新使用它们来表示 ID。这很糟糕,因为将同一事物用于两个目的会让人感到困惑,而且因为 ID 是数字并且应该存储在 int 变量中。当然,当错误检查失败并且不存在的客户名称被传递到 select @customer= customerid from customer where @customer= name 时,这不会选择 ID,因此 @customer 继续包含名称。然后您稍后尝试将其插入到预订字段中,其客户列是 int 列 - 因此您无法将 varchar(即文本)值插入整数字段的错误。

作为一种好的做法,我建议您这样做

a) 创建单独的整数变量来表示客户 ID 和酒店 ID 值。

b) 在INSERT 语句中明确声明列。 (如果您在目标表中添加或删除其他列,这将在以后为您节省时间,那么您不会遇到列的顺序或数量错误的问题。它会减少代码维护,并增加可读性。)

c) 作为更广泛的建议,我建议您的存储过程实际上接受客户 ID 和酒店 ID 作为输入参数,而不是名称。总是存在名称更改的危险,甚至两条记录实际上可能具有相同的名称(例如,在英国文化中,有两个名为 John Smith 的客户一点也不奇怪),这意味着您可能选择了错误的 ID。我假设您的数据库前面有一个用户界面。用户应该可以在 UI 中选择一个客户——可能是从下拉列表或自动完成中,并且 UI 可以知道这与哪个客户 ID 相关。如果是新客户,则用户必须先创建新客户记录,然后才能继续进行其余的预订流程。大多数专业开发的应用程序都遵循这种方法(关于从现有记录中进行选择)。因此,在用户选择或创建客户后,生成的客户 ID 将被提供给存储过程,而不是名称。这样一来,对于哪个客户进行预订,绝对没有任何歧义的余地。

【讨论】:

    【解决方案3】:
    create PROCEDURE spNieuweReservering
    ( 
       @customer VARCHAR(255), 
       @date1 date,
       @date2 date,
       @hotel varchar(40),
       @count_person int ,
       @emplyeeid int,
       @roomid int
    
    ) 
    AS 
    BEGIN 
       DECLARE @bookdate date    
       SET NOCOUNT ON;
       begin transaction MainTrans
    IF not exists (SELECT count(*)  FROM customer WHERE @customer= name ) BEGIN 
        raiserror('Deze klant bestaat niet. Controleer de naam of maak een nieuwe klant aan.',16,1)
    END 
    BEGIN
       select @customer= customerid
       from customer
       where @customer= name
    
       select @hotel = hotelid
       from hotel
       where @hotel = location
    
       SELECT @bookdate= GETDATE()
       FROM boeking 
    
       INSERT INTO booking values (@bookdate, @count_person, null, @customer, @hotel, @employeeid)
       insert into roombooking values (@roomid, @date1, @date2, null, null)
    END
    IF @@ERROR <> 0
    BEGIN
        rollback TRANSACTION MainTrans
        raiserror('Er is een fout opgetreden bij het toevoegen van de reservering. Controleer de input',16,1)
        return
    END
    ELSE
              BEGIN
                 COMMIT TRANSACTION MainTrans               
              END
    END 
    

    【讨论】:

    • 解释一下您为解决此问题所做的更改会很有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多