【问题标题】:T-SQL Error Message 207 When passing values Dynamically动态传递值时出现 T-SQL 错误消息 207
【发布时间】:2018-11-08 23:54:17
【问题描述】:

我正在尝试创建一个允许将值传递给它的存储过程,但是,当我尝试使用动态 T-SQL 时,我会引发错误 MSG 207

由于以下网站,我知道错误消息应该表明我的语句中的列名拼写错误:

https://www.tsql.info/error/msg-207-level-16-invalid-column-name.php

然而,这没有意义,因为下面的硬编码语句可以正常工作。

INSERT INTO [dbo].[tDriversLicense] (DriversLicensePrefix,    DriversLicenseSuffix, DateAdded, DriversLicenseNumber)
    VALUES ('shockc', '11653798', GETDATE(), 'GAD4859');

ALTER PROCEDURE [dbo].[spAddDriversLicense]
    -- Add the parameters for the stored procedure here
    @DriversLicensePrefix NCHAR(8),
    @DriversLicenseSuffix NCHAR(10)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

            DECLARE @sqlInsertDriversLicense NVARCHAR(MAX)
            SET @sqlInsertDriversLicense = 'INSERT INTO [dbo].[tDriversLicense] (DriversLicensePrefix, DriversLicenseSuffix, DateAdded, DriversLicenseNumber)
                VALUES (' + @DriversLicensePrefix + ', ' + @DriversLicenseSuffix + ', GETDATE(), GPC4859);'

            EXECUTE sp_executesql @sqlInsertDriversLicense

END

我已经将这段代码溢出了好几个小时,我对为什么两个 INSERT 语句之间有任何区别感到非常困惑。传递的值是相同的,但是当我尝试动态传递它们时会引发错误。这如何引发错误??

我使用该视频中的一些代码来尝试学习如何动态传递标量值,并在其他存储过程中获得了运气。

https://www.youtube.com/watch?v=RHHKG65WEoU

【问题讨论】:

  • 动态 SQL 插入中的所有值都没有单引号。 @shockemc
  • 向变量添加单引号会将它们作为字符串传递,违背了将它们作为参数传递的目的......不是吗? @马克克拉姆
  • 也许,但这会导致您的错误。打印出@/sqlInsertDriversLicense 变量的内容,您将看到问题所在。无论哪种方式,您都应该考虑使用参数而不是内联变量@shockemc
  • msg 207 你的消息是不是更像这样:"Msg 207 Invalid column name."?当提到错误消息时,请在问题中包含完整的消息。 (我不会通过数字引用记住每个 dbms 的错误消息,我相信我并不孤单。)
  • 为什么需要动态 SQL 和 EXEC?这可以直接解决...

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


【解决方案1】:

使用动态字符串时,请先选择它们,以便检查生成的语法是否可行。

结果中需要单引号,因此代码中需要的不仅仅是单引号:

declare @DriversLicensePrefix nchar(8) = 'A2345678'
declare @DriversLicenseSuffix nchar(10) = 'abcdefghij'

DECLARE @sqlInsertDriversLicense nvarchar(max)
SET @sqlInsertDriversLicense = 'INSERT INTO [dbo].[tDriversLicense] (DriversLicensePrefix, DriversLicenseSuffix, DateAdded, DriversLicenseNumber)
                VALUES (N''' + @DriversLicensePrefix + ''', N''' + @DriversLicenseSuffix + ''', ''' + convert(char(8),GETDATE(),112) + ''', ''GPC4859'');'

select @sqlInsertDriversLicense

+-------------------------------------------------------------------------------------------------------------------+
|                                                      result:                                                      |
+-------------------------------------------------------------------------------------------------------------------+
| INSERT INTO [dbo].[tDriversLicense] (DriversLicensePrefix, DriversLicenseSuffix, DateAdded, DriversLicenseNumber) |
| VALUES (N'A2345678', N'abcdefghij', '20181109', 'GPC4859');                                                         |
+-------------------------------------------------------------------------------------------------------------------+

注意您应该使用convert(char(8),getdate(),112)SQL Server 会将 YYYYMMDD 格式识别为日期值,而不管服务器默认设置如何。


上面的结果演示了插入语句必须是什么,注意它包含几个单引号。

当您连接 SQL 语句时,您也在处理字符串,并且字符串的每一部分都必须包含在单引号内。

所以单引号有多种需求。

并且;因此,您需要在整个连接过程中使用多个单引号,其中一些用于帮助形成 SQL 语句,而另一些则位于该语句的内部。

/* get this into @sql */
select 'Y' as col1;

declare @SQL as nvarchar(max)

set @SQL = N'select ''Y'' as col1;'

select @SQL;

+---------------------+
|        @SQL         |
+---------------------+
| select 'Y' as col1; |
+---------------------+

在较大的查询中,2 个变量被定义为 NCHAR(8) 或 (10),因为您已将它们定义为 Nchar,然后在将数据插入那些时,您应该在输入前加上

【讨论】:

  • 我投了赞成票,因为它解决了这个问题,但是:更好的提示是使用真实参数(见我的回答)。如果可能的话,我会避免在字符串基础上创建命令......(你可能会遇到鲍比表,-))
  • @Used_By_Already - 我将此标记为解决方案,因为它解决了所要求的问题。但是,如果您不介意,您能否解释一下为什么在必要时在引号前加上额外的单引号和 N?
  • 我添加到答案中。
  • 我会按照 Shnugo 的建议使用 CREATE PROCEDURE TestStraight 方法并尽可能避免动态 sql。
【解决方案2】:

正如评论中发布的那样,根本不需要这种动态方法。

以下代码将显示一种直接且动态的方法。试试看:

USE master;
GO
CREATE DATABASE testDB;
GO
USE testDB;
GO
CREATE TABLE TestTable(SomeContent VARCHAR(100),SomeDate DATETIME,SomeFixString VARCHAR(100));
GO

--本程序将直接使用参数。无需任何动态 SQL:

CREATE PROCEDURE TestStraight(@content VARCHAR(100))
AS
BEGIN
    INSERT INTO TestTable(SomeContent,SomeDate,SomeFixString)
    VALUES(@content,GETDATE(),'Proc Straight');
END
GO

--此过程将使用实际参数。您应该切勿在字符串连接中使用参数。有一天你可能会遇到bobby tables...

CREATE PROCEDURE TestDynamic(@content VARCHAR(100))
AS
BEGIN
    DECLARE @cmd NVARCHAR(MAX)=
    N'INSERT INTO TestTable(SomeContent,SomeDate,SomeFixString)
      VALUES(@DynamicContent,GETDATE(),''Proc Dynamic'');'
    EXEC sp_executesql @cmd,N'@DynamicContent VARCHAR(100)',@DynamicContent=@content;
END
GO

--测试一下

EXEC TestStraight 'yeah!';
EXEC TestDynamic 'oh yeah!';
SELECT * FROM TestTable;
GO

--清理

USE master;
GO
--careful with real data!
--DROP DATABASE testDB;

【讨论】:

  • @Shungo - 感谢您的输入,正如之前的评论中提到的,我使用动态 SQL 是因为我认为这是在存储过程中接受和使用用户输入的唯一方法。我认为参数只能传递给函数。我仍然不确定功能是否可以在 SP 中使用。至于 Bobby Tables,我并不是指他本人,但为了简单起见,我故意省略了我正在使用的 QUOTENAME() 函数。我将按照您的建议尽快解决此问题。
猜你喜欢
  • 2016-11-04
  • 1970-01-01
  • 1970-01-01
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 2022-01-15
相关资源
最近更新 更多