变量名称在查询批处理或存储过程中必须是唯一的吗?

Posted

技术标签:

【中文标题】变量名称在查询批处理或存储过程中必须是唯一的吗?【英文标题】:Variable names must be unique within a query batch or stored procedure? 【发布时间】:2021-12-15 17:35:05 【问题描述】:

我们如何在一个事务中运行多个 sql 脚本,其中每个脚本可能定义了相同的变量?

文件 1:

declare @tableName varchar(28), @query nvarchar(1000)
set @tableName = '1apples'+convert(varchar(28), getdate(),121)
select @query = 'select name into ' + quotename(@tableName) + ' from sys.objects'
print @query
exec (@query)
go

文件2:

declare @tableName varchar(28), @query nvarchar(1000)
set @tableName = '2apples'+convert(varchar(28), getdate(),121)
select @query = 'select name into ' + quotename(@tableName) + ' from sys.objects'
print @query
exec (@query)
 go

我在 PowerShell 中执行这样的文件:

try 

  $files = Get-ChildItem -Path $SqlFilesDirectory -File -Filter *.sql
  $filesSorted = $files |Sort-Object -Property Name
  $filesconcatenated = @(
      $files |Get-Content -Raw
  ) -join [Environment]::NewLine
  $filesconcatenated = 'SET XACT_ABORT ON ' + $filesconcatenated + ' SET XACT_ABORT OFF ' + [Environment]::NewLine
    $cmd = New-Object System.Data.SqlClient.SqlCommand ($filesconcatenated), $conn
    $cmd.Transaction = $tran
    [void]$cmd.ExecuteNonQuery()
   
  $tran.Commit()

catch 
  $tran.Rollback()
  Write-Host "Record not Inserted ->"
  $_.exception.message

finally 
  $conn.Close()

我收到以下异常:

使用“0”参数调用“ExecuteNonQuery”的异常:“不正确 关键字'declare'附近的语法。变量名“@tableName”有 已经宣布了。变量名称在查询中必须是唯一的 批处理或存储过程。变量名“@tableName”已经 被宣布。变量名称在查询批次中必须是唯一的,或者 存储过程。关键字 'SET' 附近的语法不正确。”

我们如何在一个事务中运行多个 SQL 脚本,其中每个脚本可能定义了相同的变量?

这是它尝试运行的完整脚本:

SET XACT_ABORT ON 
declare @tableName varchar(28), @query nvarchar(1000)
set @tableName = '1apples'+convert(varchar(28), getdate(),121)
select @query = 'select name into ' + quotename(@tableName) + ' from sys.objects'
print @query
exec (@query)
go
declare @tableName varchar(28), @query nvarchar(1000)
set @tableName = '2apples'+convert(varchar(28), getdate(),121)
select @query = 'select name into ' + quotename(@tableName) + ' from sys.objects'
print @query
exec (@query)
go
declare @tableName varchar(28), @query nvarchar(1000)
set @tableName = '3apples'+convert(varchar(28), getdate(),121)
select @query = 'select name into ' + quotename(@tableName) + ' from sys.objects'
print @query
exec (@query)
go
 SET XACT_ABORT OFF 

【问题讨论】:

您正在构建您之前两个问题的答案,***.com/a/69756763/45375 和 ***.com/a/69763633/45375。这些答案为那些as ask的问题提供了解决方案 - 他们也没有解决您遇到的后来问题并不是他们的缺点,并且指导您应该接受的未来读者答案取决于他们是否按要求解决了问题。 【参考方案1】:

你不能在一个批次中两次使用相同的变量

因此,通过循环数组将它们作为单独的命令执行

$connString = "Server=tcp:$ServerName.database.windows.net,1433;Database=$DBName;User Id=$SvcAdminAccount@$ServerName;Password=$SvcAdminPassword;MultipleActiveResultSets=true;Persist Security Info=true;";
$conn = New-Object System.Data.SqlClient.SqlConnection $connString try

  $conn.Open()
  $files = Get-ChildItem -Path $SqlFilesDirectory -File -Filter *.sql
  $filesSorted = $files |Sort-Object -Property Name
  $tran = $conn.BeginTransaction()
  foreach ($file in $filesSorted)
  
    $query = "SET XACT_ABORT ON; " + (Get-Content -Raw $file)
    $cmd = New-Object System.Data.SqlClient.SqlCommand ($query, $conn, $tran)
    [void]$cmd.ExecuteNonQuery()
  
  $tran.Commit();

catch 
  Write-Host "Record not Inserted ->"
  $_.exception.message

finally 
  $tran.Dispose()
  $conn.Dispose()

注意Dispose 的使用方式,而不是Rollback,因为Dispose 永远不会抛出异常。它也在finally 而不是catch

【讨论】:

以上是关于变量名称在查询批处理或存储过程中必须是唯一的吗?的主要内容,如果未能解决你的问题,请参考以下文章

数据库存储过程和触发器

在gridview行中保存选中的复选框c#asp

oracle存储过程:将select查询的结果存到变量中

Qt ObjectName()必须是唯一的吗?

使用 for 循环将多条记录插入 SQL Server 数据库

表变量