จะใช้ตัวแปรสำหรับชื่อฐานข้อมูลใน T-SQL ได้อย่างไร?


123

ฉันใช้ชื่อฐานข้อมูลในหลาย ๆ ที่ในสคริปต์ของฉันและฉันต้องการที่จะเปลี่ยนแปลงได้อย่างรวดเร็วดังนั้นฉันจึงมองหาสิ่งนี้:

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

แต่มันไม่ได้ผล แล้ววิธีที่ถูกต้องในการเขียนโค้ดนี้คืออะไร?

คำตอบ:


135

ใส่สคริปต์ทั้งหมดลงในสตริงเทมเพลตโดยมีตัวยึดตำแหน่ง {SERVERNAME} จากนั้นแก้ไขสตริงโดยใช้:

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

จากนั้นเรียกใช้ด้วย

EXECUTE (@SQL_SCRIPT)

ยากที่จะเชื่อว่าตลอดสามปีที่ผ่านมาไม่มีใครสังเกตเห็นว่ารหัสของฉันใช้ไม่ได้ !

คุณไม่สามารถEXECหลายแบทช์ GOเป็นตัวคั่นชุดงานไม่ใช่คำสั่ง T-SQL จำเป็นต้องสร้างสตริงที่แยกจากกันสามสตริงจากนั้นให้EXECแต่ละสตริงหลังจากการแทนที่

ฉันคิดว่าคน ๆ หนึ่งสามารถทำบางสิ่งที่ "ฉลาด" ได้โดยการแยกสตริงเทมเพลตเดียวออกเป็นหลายแถวโดยการแยกGO; ฉันทำเสร็จแล้วในรหัส ADO.NET

แล้วฉันได้คำว่า "SERVERNAME" มาจากไหน?

นี่คือรหัสบางส่วนที่ฉันเพิ่งทดสอบ (และใช้งานได้):

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 วิธีการที่ดีมาก ... คุณเพิ่งช่วยฉันจากการทำงานมากมายขอบคุณ ... แม้ว่ามันควรจะเป็น EXECUTE (@SQL_SCRIPT) หรืออย่างน้อยนั่นก็เป็นสิ่งที่ได้ผลสำหรับฉัน
reSPAWNed

2
ต้องระมัดระวังในการหลบหนีแม้ว่า
usr

4
SYSNAMEจะเป็นประเภทข้อมูลที่เหมาะสมกว่าที่VARCHAR(255)ควรใช้QUOTENAMEเพื่อจัดการกับชื่อฐานข้อมูลที่เป็นไปได้ทั้งหมด (และอาจป้องกันการฉีด SQL ขึ้นอยู่กับแหล่งที่มาของชื่อ)
Martin Smith

1
ใช้ไม่ได้ถ้าฉันต้องการCREATE SCHEMAในฐานข้อมูลอื่นโดยใช้USE {DBNAME}ไฟล์. Schema สร้างในฐานข้อมูลที่ไม่ถูกต้อง /
Bomberlt

103

คุณยังสามารถใช้sqlcmdโหมดนี้ (เปิดใช้งานในเมนู "แบบสอบถาม" ใน Management Studio)

:setvar dbname "TEST" 

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

แก้ไข:

ตรวจสอบบทความMSDNนี้เพื่อตั้งค่าพารามิเตอร์ผ่านเครื่องมือ SQLCMD


1
วิธีนี้ใช้ตัวแปรที่ประกาศไปแล้วได้อย่างไร แทน "TEST" คุณสามารถเพิ่ม @dbName ได้ไหม ฉันลองแล้วไม่ได้ผล
syclee

1
@syclee ตัวแปร TSQL? ไม่มีการแทนที่ sqlcmd ก่อนที่สคริปต์จะถูกส่งไปยังเซิร์ฟเวอร์
Martin Smith

@MartinSmith เฮ้ฉันต้องการชื่อ db เป็นคำสั่ง OUTPUT ฉันจะใช้ SQLCMD ได้อย่างไร?
Kunal Kakkad

12

ขออภัยที่คุณไม่สามารถประกาศชื่อฐานข้อมูลด้วยตัวแปรในรูปแบบนั้นได้

สำหรับสิ่งที่คุณกำลังพยายามทำให้สำเร็จคุณจะต้องห่องบของคุณไว้ในคำสั่ง EXEC () ดังนั้นคุณจะมีสิ่งที่ต้องการ:

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

แล้วโทร

EXECUTE(@Sql) or sp_executesql(@Sql)

เพื่อดำเนินการสตริง sql


EXECมองหาขั้นตอนการจัดเก็บ ในกรณีEXECUTEนี้จำเป็น
Bob Blogge

2
อันที่จริงฉันต้องขอโทษ ปรากฎEXECและEXECUTEเหมือนกัน ฉันทำคำสั่งหลังจากที่ล้มเหลวEXECและประสบความสำเร็จด้วยEXECUTE. แม้ว่าจะเห็นได้ชัดว่าปัญหาที่แท้จริงของฉันไม่เกี่ยวข้องกับทั้งสองอย่าง
Bob Blogge

2
อย่าทำสิ่งนี้ในการผลิต ...
Magic Octopus Urn

@MagicOctopusUrn โพสต์เก่าและความคิดเห็นแตกต่างกันมาก แต่ฉันอยากรู้ว่าทำไมไม่? มันไม่ควรเจาะจง ??
รุนแรง

@MagicOctopusUrn นั่นเป็นเพราะศักยภาพในการฉีดหรือเปล่า?
Isaac Reefman

5

คุณไม่สามารถใช้ตัวแปรในคำสั่งสร้างตาราง สิ่งที่ดีที่สุดที่ฉันสามารถแนะนำได้คือการเขียนแบบสอบถามทั้งหมดเป็นสตริงและดำเนินการนั้น

ลองทำสิ่งนี้:

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

exec (@query);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.