在下面的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
这是错误:
答案 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'
样本调用的示例输出。