Jak używać zmiennej dla nazwy bazy danych w T-SQL?

123

Używam nazwy bazy danych w kilku miejscach w moim skrypcie i chcę mieć możliwość szybkiej zmiany, więc szukam czegoś takiego:

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

Ale to nie działa. Jaki jest więc prawidłowy sposób pisania tego kodu?

Erick Sasse
źródło

Odpowiedzi:

135

Umieść cały skrypt w ciągu szablonu, z symbolami zastępczymi {SERVERNAME}. Następnie edytuj ciąg używając:

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

a następnie uruchom go z

EXECUTE (@SQL_SCRIPT)

Aż trudno uwierzyć, że w ciągu trzech lat nikt nie zauważył, że mój kod nie działa !

Nie możesz EXECwiele partii. GOjest separatorem wsadowym, a nie instrukcją T-SQL. Konieczne jest zbudowanie trzech oddzielnych ciągów, a następnie EXECkażdego po podstawieniu.

Przypuszczam, że można by zrobić coś „sprytnego”, dzieląc pojedynczy ciąg szablonu na wiele wierszy przez podział GO; Zrobiłem to w kodzie ADO.NET.

Skąd mam słowo „SERVERNAME”?

Oto kod, który właśnie przetestowałem (i który działa):

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)
John Saunders
źródło
2
+1 Bardzo fajne podejście ... Właśnie uratowałeś mi mnóstwo pracy, dzięki ... Chociaż powinno być EXECUTE (@SQL_SCRIPT), a przynajmniej tak mi się udało.
SPAWNED
2
Trzeba jednak uważać z ucieczką.
usr
4
SYSNAMEbyłby bardziej odpowiednim typem danych niż VARCHAR(255)powinien być używany QUOTENAMEdo radzenia sobie ze wszystkimi możliwymi nazwami baz danych (i prawdopodobnie do zapobiegania wstrzykiwaniu SQL w zależności od źródła nazwy)
Martin Smith
1
Nie działa, jeśli chcę, CREATE SCHEMAw innej bazie danych, używając USE {DBNAME}. Schemat tworzy się w złej bazie danych; /
Bomberlt
103

Możesz również użyć sqlcmddo tego trybu (włącz go w menu „Zapytanie” w Management Studio).

:setvar dbname "TEST" 

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

EDYTOWAĆ:

Sprawdź ten artykuł MSDN, aby ustawić parametry za pomocą narzędzia SQLCMD.

Martin Smith
źródło
1
jak ta metoda może używać już zadeklarowanych zmiennych? Czy zamiast „TESTU” można dodać @dbName? Próbowałem i nie
działałem
1
@syclee Zmienna TSQL? Nie, podstawienia sqlcmd są wykonywane przed wysłaniem skryptu na serwer.
Martin Smith,
@MartinSmith Hej, chcę nazwę db jako polecenie OUTPUT. Więc jak mogę to mieć przy użyciu SQLCMD.?
Kunal Kakkad
12

Niestety nie możesz zadeklarować nazw baz danych ze zmienną w tym formacie.

W przypadku tego, co próbujesz osiągnąć, będziesz musiał zawrzeć swoje instrukcje w instrukcji EXEC (). Więc miałbyś coś takiego:

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

Wtedy zadzwoń

EXECUTE(@Sql) or sp_executesql(@Sql)

aby wykonać łańcuch sql.

Dillie-O
źródło
EXECszuka procedury składowanej. W takim przypadku EXECUTEjest potrzebny.
Bob Blogge
2
Właściwie to muszę przeprosić. Okazuje się EXECi EXECUTEsą takie same. Złożyłem oświadczenie po niepowodzeniu EXECi sukcesie EXECUTE. Chociaż oczywiście mój prawdziwy problem nie był związany z żadnym z nich.
Bob Blogge,
2
Nie rób tego w produkcji ... Nigdy.
Urna Magicznej Ośmiornicy
@MagicOctopusUrn różni się starym postem i bardzo komentarzami, ale jestem ciekawy, dlaczego nie? czy nie powinno to być specyficzne dla wymagań?
Ostry
@MagicOctopusUrn Czy to z powodu możliwości wstrzyknięcia?
Isaac Reefman
5

Nie można używać zmiennej w instrukcji tworzenia tabeli. Najlepszą rzeczą, jaką mogę zasugerować, jest napisanie całego zapytania jako łańcucha i wykonanie tego.

Spróbuj czegoś takiego:

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

exec (@query);
Andrew Hare
źródło