SQL中@@变量的范围

时间:2014-02-25 17:46:50

标签: sql-server tsql

在下面的TSQL代码中,我可以在前几行使用我的局部变量,然后我再也不能使用它了。为什么我无法在代码的最后一行使用它?

它的范围在哪里结束?

DECLARE @@CurrentDB varchar(50);
SET @@CurrentDB = 'MyDBNAME';



-- Find Data & Log Fiel locations
SELECT DB_NAME(database_id) AS DatabaseName, name AS LogicalFileName, physical_name AS PhysicalFileName, size/(128*1024) [GB] 
FROM sys.master_files AS mf
WHERE DB_NAME(database_id) = @@CurrentDB

-- Detach DB
USE
GO
ALTER DATABASE  SET  SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
USE [master]
GO
EXEC master.dbo.sp_detach_db @dbname = @@Cur
GO

这是错误: enter image description here

3 个答案:

答案 0 :(得分:3)

每次向SQL Server传递GO命令时,都会结束变量存在的上下文,并且在T-SQL代码中的该点之后不再可以访问该变量。 SQL Server中不存在“全局”变量,但通常可以通过实现全局变量表(临时或永久)来实现它。

您可以从此blog帖子中获得一般概念,该帖子设置永久表来跟踪全局变量。

答案 1 :(得分:0)

作为解决方法,您可以使用Global Temp Table

Declare @CurrentDB varchar(50)
SET @CurrentDB = 'MyDBNAME'
Create Table ##CurrentDB (Name varchar(50))
Insert Into ##CurrentDB Values (@CurrentDB)
GO
-- ...
GO
Declare @CurrentDB varchar(50)
Select Top 1 @CurrentDB = Name From ##CurrentDB 
Select @CurrentDB

即使您在脚本的每个部分使用不同的数据库,这也应该有效。

答案 2 :(得分:0)

为什么要使用全局变量或临时表?这使我成为用户定义的存储过程。

以下是业务规则。

1 - 您基本上想要获取要分离的数据库的位置和大小。

2 - 想要将数据库设置为单用户模式。

3 - 您想要分离数据库。请记住,文件将在之后徘徊。

我在MSDB数据库中创建了它,但您可以将它放在您自己的工具箱数据库中。

我没有检查数据库是否真的只使用模式。 - TODO列表

只需检查sys.databases表中的模式即可。如果ALTER失败,请不要尝试分离。只需通知用户找到spid并将其杀死。

http://technet.microsoft.com/en-us/library/ms178534.aspx

4 - 我没有在中进行任何错误处理。 - TODO list

最后但同样重要的是,此解决方案可能容易出现SQL注入,不会让全世界访问。

简而言之,下面的存储过程就是您想要的。

--
-- Create a user stored procedure
--

-- Start in msdb
use msdb
go

-- drop existing
if object_id('my_detach_process') > 0
drop procedure my_detach_process
go

-- create new
create procedure my_detach_process(@dbname sysname)
as

  -- Show the data
  SELECT 
    DB_NAME(mf.database_id) AS DatabaseName, 
    mf.name AS LogicalName, 
    mf.physical_name AS PhysicalName, mf.size as SizeMb
  FROM sys.master_files AS mf
  WHERE DB_NAME(database_id) = @dbname;

  -- Set to single user
  DECLARE @sqlstmt1 nvarchar(512) = '';
  SET @sqlstmt1 = 'ALTER DATABASE [' + @dbname + '] SET SINGLE_USER WITH ROLLBACK IMMEDIATE';
  EXEC sp_executesql @sqlstmt1;

  -- Detach
  DECLARE @sqlstmt2 nvarchar(512) = '';
  SET @sqlstmt2 = 'USE [master]; EXEC master.dbo.sp_detach_db @dbname = ' + @dbname;
  EXEC sp_executesql @sqlstmt2;

GO


--
-- Sample call
--

-- Choose master
use master
go

-- Create toy db
create database toy;
go

-- Call the sp
exec msdb.dbo.my_detach_process @dbname = 'Toy'

样本调用的示例输出。

enter image description here