【问题标题】:SQL Server: stored procedure not working, but works outside of stored procedureSQL Server:存储过程不工作,但在存储过程之外工作
【发布时间】:2020-03-15 01:47:34
【问题描述】:

SQL Server:以下存储过程不工作,但 SQL 语句在存储过程之外工作。

CREATE PROCEDURE schema1.dropConstraints
      (@schemaName AS nvarchar, @tableName AS nvarchar) 
AS
BEGIN
    DECLARE @cname nvarchar(80)
    DECLARE @sqlStatement nvarchar(100)

    DECLARE myCursor CURSOR LOCAL FOR
        SELECT constraint_name 
        FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
        WHERE constraint_schema = @schemaName 
          AND table_name = @tableName;

    OPEN myCursor;
    FETCH NEXT FROM myCursor INTO @cname;

    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @sqlStatement = 'ALTER TABLE ' + @schemaName + '.' + @tableName + ' DROP CONSTRAINT ' + @cname;
        EXEC sp_executesql @sqlStatement;

        FETCH NEXT FROM myCursor INTO @cname;
    END;

    CLOSE myCursor;
    DEALLOCATE myCursor;
END;

调用存储过程

exec schema1.dropConstraints 'schema1', 'Foo';

Foo 的约束(PK、FK)未被删除。没有错误。

但是在存储过程之外运行代码,它工作正常。

    DECLARE @schemaName nvarchar(80) = 'schema1';
    DECLARE @tableName nvarchar(80) = 'Foo';

    DECLARE @cname nvarchar(80)
    DECLARE @sqlStatement nvarchar(100)

    DECLARE myCursor CURSOR LOCAL FOR 
        SELECT constraint_name 
        FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
        WHERE constraint_schema = @schemaName AND table_name = @tableName;

    OPEN myCursor;
    FETCH NEXT FROM myCursor INTO @cname;

    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @sqlStatement = 'ALTER TABLE ' + @schemaName + '.' + @tableName + ' DROP CONSTRAINT ' + @cname;
        EXEC sp_executesql @sqlStatement;

        FETCH NEXT FROM myCursor INTO @cname;
    END;

    CLOSE myCursor;
    DEALLOCATE myCursor;

这行得通。表Foo 的约束(PK、FK)被删除。有什么区别?

登录:sa。

【问题讨论】:

  • 虽然可能不是问题的原因,但 OPENCLOSEDEALLOCATE 语句之间的游标名称不一致(myCursor vs c)。
  • 旁注:对于类似模式或表名的标识,请使用sysname。不要在查询字符串中使用不带引号的标识符。它是专门用于对象标识符的特殊数据类型。并使用quotename() 引用它们。否则,如果为您的程序提供的标识符不是简单的标识符,甚至是恶意格式错误从而启用注入,您就会遇到问题。
  • 您没有为 nvarchar 数据类型参数指定长度。默认长度为 1,因此指定的值被截断。就个人而言,我会像建议的@stickybit 一样使用sysname,它是nvarchar(128) 的同义词,并与SQL Server 对象和列名对齐。
  • @EdHarper 光标名称已修复。
  • 添加 PRINT @sqlStatement 以检查 NVARCHAR 长度是否是问题

标签: sql-server stored-procedures


【解决方案1】:

这些参数数据类型声明中缺少最大字符长度:

CREATE PROCEDURE schema1.dropConstraints
      (@schemaName AS nvarchar, @tableName AS nvarchar) 

因为默认长度为 1,所以提供的值被静默截断为单个字符,结果与预期不符。

确保参数数据类型和长度与引用列的匹配是一种很好的做法。对于INFORMATION_SCHEMA 视图,请查阅documentation,您会发现合适的数据类型是nvarchar(128)。就个人而言,我喜欢在 SQL Server 中使用sysname 作为标识符类型,它是nvarchar(128) 的同义词。

CREATE PROCEDURE schema1.dropConstraints
      @schemaName AS sysname, @tableName AS sysname

【讨论】:

  • 谢谢。将数据类型更改为 sysname 有效。但是以“DF_”开头的约束没有被删除。这些限制是什么?我没有明确添加这些。
  • 从名称来看,这些看起来像是默认约束。见this answer。考虑改用目录视图,因为它们将公开所有 SQL Server 功能,尽管是专有的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-13
  • 2014-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多