Làm cách nào để sử dụng biến cho tên cơ sở dữ liệu trong T-SQL?


123

Tôi sử dụng tên cơ sở dữ liệu ở một số vị trí trong tập lệnh của mình và tôi muốn có thể nhanh chóng thay đổi nó, vì vậy tôi đang tìm kiếm một cái gì đó như thế này:

DECLARE @DBNAME VARCHAR(50)
SET @DBNAME = 'TEST'

CREATE DATABASE @DBNAME
GO
ALTER DATABASE @DBNAME SET COMPATIBILITY_LEVEL = 90
GO
ALTER DATABASE @DBNAME SET RECOVERY SIMPLE 
GO

Nhưng nó không hoạt động. Vì vậy, cách chính xác để viết mã này là gì?

Câu trả lời:


135

Đặt toàn bộ tập lệnh vào một chuỗi mẫu, với các trình giữ chỗ {SERVERNAME}. Sau đó chỉnh sửa chuỗi bằng:

SET @SQL_SCRIPT = REPLACE(@TEMPLATE, '{SERVERNAME}', @DBNAME)

và sau đó chạy nó với

EXECUTE (@SQL_SCRIPT)

Thật khó để tin rằng, trong ba năm, không ai nhận thấy rằng mã của tôi không hoạt động !

Bạn không thể EXECnhiều đợt. GOlà một dấu tách hàng loạt, không phải là câu lệnh T-SQL. Cần phải xây dựng ba chuỗi riêng biệt, sau đó đến EXECtừng chuỗi sau khi thay thế.

Tôi cho rằng người ta có thể làm điều gì đó "thông minh" bằng cách chia chuỗi mẫu đơn thành nhiều hàng bằng cách tách trên GO; Tôi đã thực hiện điều đó trong mã ADO.NET.

Và tôi đã lấy từ "SERVERNAME" từ đâu?

Đây là một số mã mà tôi vừa thử nghiệm (và nó hoạt động):

DECLARE @DBNAME VARCHAR(255)
SET @DBNAME = 'TestDB'

DECLARE @CREATE_TEMPLATE VARCHAR(MAX)
DECLARE @COMPAT_TEMPLATE VARCHAR(MAX)
DECLARE @RECOVERY_TEMPLATE VARCHAR(MAX)

SET @CREATE_TEMPLATE = 'CREATE DATABASE {DBNAME}'
SET @COMPAT_TEMPLATE='ALTER DATABASE {DBNAME} SET COMPATIBILITY_LEVEL = 90'
SET @RECOVERY_TEMPLATE='ALTER DATABASE {DBNAME} SET RECOVERY SIMPLE'

DECLARE @SQL_SCRIPT VARCHAR(MAX)

SET @SQL_SCRIPT = REPLACE(@CREATE_TEMPLATE, '{DBNAME}', @DBNAME)
EXECUTE (@SQL_SCRIPT)

SET @SQL_SCRIPT = REPLACE(@COMPAT_TEMPLATE, '{DBNAME}', @DBNAME)
EXECUTE (@SQL_SCRIPT)

SET @SQL_SCRIPT = REPLACE(@RECOVERY_TEMPLATE, '{DBNAME}', @DBNAME)
EXECUTE (@SQL_SCRIPT)

2
+1 Cách tiếp cận rất hay ... Bạn vừa cứu tôi khỏi hàng tấn công việc, thx ... Mặc dù đó phải là EXECUTE (@Query_SCRIPT), hoặc ít nhất đó là những gì hiệu quả với tôi.
reSPAWNed

2
Cần phải cẩn thận với thoát, mặc dù.
usr

4
SYSNAMEsẽ là một kiểu dữ liệu phù hợp hơn VARCHAR(255)cũng nên sử dụng QUOTENAMEđể xử lý tất cả các tên cơ sở dữ liệu có thể (và có thể để ngăn chặn việc tiêm SQL tùy thuộc vào nguồn của tên)
Martin Smith

1
Không hoạt động nếu tôi muốn CREATE SCHEMAtrong cơ sở dữ liệu khác, sử dụng USE {DBNAME}. Lược đồ tạo trong cơ sở dữ liệu sai; /
Bomberlt

103

Bạn cũng có thể sử dụng sqlcmdchế độ cho việc này (bật chế độ này trên menu "Truy vấn" trong Studio quản lý).

:setvar dbname "TEST" 

CREATE DATABASE $(dbname)
GO
ALTER DATABASE $(dbname) SET COMPATIBILITY_LEVEL = 90
GO
ALTER DATABASE $(dbname) SET RECOVERY SIMPLE 
GO

BIÊN TẬP:

Kiểm tra bài viết MSDN này để đặt tham số thông qua công cụ SQLCMD.


1
Làm thế nào phương pháp này có thể sử dụng các biến đã khai báo? Thay vì "KIỂM TRA", bạn có thể thêm @dbName không? Tôi đã thử và không làm việc
sycle

1
@sycle Một biến TSQL? Không có sự thay thế sqlcmd nào được thực hiện trước khi tập lệnh thậm chí được gửi đến máy chủ.
Martin Smith

@MartinSmith Này, tôi muốn tên db là lệnh OUTPUT. Vậy làm thế nào tôi có thể có nó bằng SQLCMD.?
Kunal Kakkad

12

Thật không may, bạn không thể khai báo tên cơ sở dữ liệu với một biến trong định dạng đó.

Đối với những gì bạn đang cố gắng thực hiện, bạn sẽ cần phải bọc các câu lệnh của mình trong câu lệnh EXEC (). Vì vậy, bạn có một cái gì đó như:

DECLARE @Sql varchar(max) ='CREATE DATABASE ' + @DBNAME

Sau đó gọi

EXECUTE(@Sql) or sp_executesql(@Sql)

để thực hiện chuỗi sql.


EXECtìm kiếm một thủ tục lưu trữ Trong trường hợp EXECUTEnày là cần thiết.
Bob Blogge

2
Thật ra tôi cần phải xin lỗi. Hóa ra EXECEXECUTEgiống nhau. Tôi đã tuyên bố sau khi thất bại EXECvà thành công với EXECUTE. Mặc dù rõ ràng vấn đề thực sự của tôi cũng không liên quan đến.
Bob Blogge

2
Đừng làm điều này trong sản xuất ... Bao giờ.
Bạch tuộc ma thuật Urn

@MagicOctopusUrn thay đổi bài cũ và rất bình luận nhưng tôi tò mò biết tại sao không? không nên yêu cầu cụ thể ??
Harsh

@MagicOctopusUrn Có phải vì khả năng tiêm?
Isaac Reefman

5

Bạn không thể sử dụng một biến trong một câu lệnh tạo bảng. Điều tốt nhất tôi có thể đề xuất là viết toàn bộ truy vấn dưới dạng một chuỗi và thực hiện điều đó.

Hãy thử một cái gì đó như thế này:

declare @query varchar(max);
set @query = 'create database TEST...';

exec (@query);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.