Gibt es eine Möglichkeit, ein Erstellungsskript ausschließlich in T-SQL aus einer vorhandenen Tabelle zu generieren (dh ohne Verwendung von SMO, da T-SQL keinen Zugriff auf SMO hat)? Angenommen, eine gespeicherte Prozedur empfängt einen Tabellennamen und gibt eine Zeichenfolge zurück, die das Erstellungsskript für die angegebene Tabelle enthält.
Lassen Sie mich nun die Situation beschreiben, mit der ich konfrontiert bin, da es einen anderen Weg geben kann, dies zu tun. Ich habe eine Instanz mit mehreren Dutzend Datenbanken. Diese Datenbanken haben alle dasselbe Schema, dieselben Tabellen, denselben Index usw. Sie wurden im Rahmen einer Softwareinstallation eines Drittanbieters erstellt. Ich muss eine Möglichkeit haben, mit ihnen zu arbeiten, damit ich Daten von ihnen ad-hoc aggregieren kann. Nette Leute bei dba.se haben mir hier schon geholfen Wie erstelle ich einen Trigger in einer anderen Datenbank?
Derzeit muss ich einen Weg finden, eine Auswahl aus einer Tabelle in allen Datenbanken zu treffen. Ich habe alle Datenbanknamen in einer Tabelle mit dem Namen aufgezeichnet Databasees
und das folgende Skript geschrieben, um eine select-Anweisung für alle von ihnen auszuführen:
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp
select * into #tmp from Database1.dbo.Table1 where 1=0
DECLARE @statement nvarchar(max) =
N'insert into #tmp select * from Table1 where Column1=0 and Cloumn2 =1'
DECLARE @LastDatabaseID INT
SET @LastDatabaseID = 0
DECLARE @DatabaseNameToHandle varchar(60)
DECLARE @DatabaseIDToHandle int
SELECT TOP 1 @DatabaseNameToHandle = Name,
@DatabaseIDToHandle = Database_Ref_No
FROM Databasees
WHERE Database_Ref_No > @LastDatabaseID
ORDER BY Database_Ref_No
WHILE @DatabaseIDToHandle IS NOT NULL
BEGIN
DECLARE @sql NVARCHAR(MAX) = QUOTENAME(@DatabaseNameToHandle) + '.dbo.sp_executesql'
EXEC @sql @statement
SET @LastDatabaseID = @DatabaseIDToHandle
SET @DatabaseIDToHandle = NULL
SELECT TOP 1 @DatabaseNameToHandle = Name,
@DatabaseIDToHandle = Database_Ref_No
FROM Databasees
WHERE Database_Ref_No > @LastDatabaseID
ORDER BY Database_Ref_No
END
select * from #tmp
DROP TABLE #tmp
Das obige Skript schlägt jedoch mit der folgenden Meldung fehl:
Ein expliziter Wert für die Identitätsspalte in der Tabelle '#tmp' kann nur angegeben werden, wenn eine Spaltenliste verwendet wird und IDENTITY_INSERT auf ON gesetzt ist.
Dies hinzufügen:
SET IDENTITY_INSERT #tmp ON
hilft nicht, da ich die Spaltenliste nicht spezifizieren und generisch halten kann.
In SQL gibt es keine Möglichkeit, die Identität für eine bestimmte Tabelle auszuschalten. Sie können nur eine Spalte löschen und eine Spalte hinzufügen, was natürlich die Spaltenreihenfolge ändert. Und wenn sich die Spaltenreihenfolge ändert, müssen Sie erneut die Spaltenliste angeben, die je nach der von Ihnen abgefragten Tabelle unterschiedlich ist.
Daher überlegte ich, ob ich den Scrip create table in meinem T-SQL-Code abrufen und mit Zeichenfolgenmanipulationsausdrücken bearbeiten könnte, um die Identitätsspalte zu entfernen und dem Resultset auch eine Spalte für den Datenbanknamen hinzuzufügen .
Kann sich jemand einen relativ einfachen Weg vorstellen, um das zu erreichen, was ich will?
quelle
Es ist in T-SQL nicht möglich, ein vollständiges Erstellungsskript einer Tabelle zu generieren. Zumindest gibt es keine Einbauten. Sie könnten immer Ihren eigenen "Generator" schreiben, der die Informationen durchgeht
sys.columns
.In Ihrem Fall benötigen Sie jedoch nicht das vollständige Erstellungsskript. Sie müssen lediglich verhindern
SELECT INTO
, dass die Identitätseigenschaft kopiert wird. Am einfachsten ist es, dieser Spalte eine Berechnung hinzuzufügen. Also stattdu musst schreiben
Um diese Anweisung zu generieren, können Sie wieder sys.columns wie in dieser SQL-Geige verwenden
MS SQL Server 2008-Schema-Setup :
Die zwei Spalten, die wir benötigen, sind
name
undis_identity
: Abfrage 1 :Ergebnisse :
Damit können wir eine
CASE
Anweisung verwenden, um jede Spalte für die Spaltenliste zu generieren:Abfrage 2 :
Ergebnisse :
Mit ein wenig XML-Trick können wir all dies zusammenfassen, um die vollständige Spaltenliste zu erhalten:
Abfrage 3 :
Ergebnisse :
Bedenken Sie, dass Sie keine #temp-Tabelle mit dynamischem SQL erstellen und außerhalb dieser Anweisung verwenden können, da die #temp-Tabelle nach Abschluss Ihrer dynamischen SQL-Anweisung den Gültigkeitsbereich verlässt. Sie müssen also entweder Ihren gesamten Code in dieselbe dynamische SQL-Zeichenfolge packen oder eine echte Tabelle verwenden. Wenn Sie in der Lage sein müssen, mehrere dieser Skripte / Prozeduren gleichzeitig auszuführen, müssen Sie uns einen zufälligen Tabellennamen geben, sonst treten sie aufeinander. So etwas
QUOTENAME(N'temp_'+CAST(NEWID() AS NVARCHAR(40))
sollte einen guten Namen machen.Anstatt alle Daten zu kopieren, können Sie auch eine ähnliche Technik verwenden, um automatisch eine Ansicht für jede Tabelle zu generieren, die alle Inkarnationen dieser Tabelle in allen Datenbanken vereint. Abhängig von der Tischgröße kann dies jedoch schneller oder langsamer sein, daher sollten Sie es testen. Wenn Sie diesen Weg gehen, würde ich diese Ansichten in eine separate Datenbank stellen.
quelle
Im SQLServerCentral-Artikel finden Sie ein gutes Skript, um dies zu erreichen:
Die aktuellste Version des Skripts ist auch als Text hier verfügbar (stormrage.com).
Ich wünschte, es gäbe eine Möglichkeit, das gesamte Skript hier einzuschließen, da es für mich funktioniert. Das Skript ist einfach zu lang, um es hier einzufügen.
Urheberrechtshinweis:
quelle
Sie können
CREATE TABLE
mithilfe von dynamischem SQL aus den Daten in ein Grobformat generierenINFORMATION_SCHEMA.COLUMNS
.Wenn Sie Einschränkungen usw. hinzufügen müssen, müssen Sie Informationen aus einigen anderen
INFORMATION_SCHEMA
Ansichten hinzufügen .Microsoft-Dokumentation
quelle