Zweck
Fügt alle Datenbanken in einem Verzeichnis dem SQL Server hinzu.
Dies wird oftmals für schnelle Server Umzüge genutzt.
Hinweise zur Verwendung
-
Ausführungsumgebung: Das Skript muss auf einem Windows-basierten SQL Server mit aktivierten
xp_cmdshell-Berechtigungen (sysadmin) ausgeführt werden. -
Test vor Produktion: Führen Sie das Skript zuerst mit einer Kopie der MDF-Dateien aus, um unerwartete Seiteneffekte zu vermeiden.
-
Transaktionslogs: Nach einem
CREATE DATABASE ... FOR ATTACHwird das zugehörige Logfile (.ldf) erwartet. Wenn es fehlt, versucht SQL Server, ein neues Log zu erstellen – dies kann fehlschlagen, wenn die Datenbank nicht ordnungsgemäß heruntergefahren wurde. -
Berechtigungen: Der SQL Server-Dienst muss Lese- und Schreibzugriff auf das Verzeichnis
@AttachFromDirhaben. -
Keine Unterstützung für Dateigruppen: Das Skript ignoriert sekundäre Dateien (
.ndf). Datenbanken mit mehreren Dateigruppen können nicht korrekt angehängt werden.
-- =====================================================================
-- Skript: Automatisches Anhängen von Datenbanken aus einem Verzeichnis
-- Autor: (Ihr Name)
-- Datum: (aktuelles Datum)
--
-- Zweck:
-- Durchsucht ein angegebenes Verzeichnis nach .mdf-Dateien und hängt
-- jede Datenbank an die aktuelle SQL Server-Instanz an, sofern:
-- - Die Datenbank noch nicht existiert.
-- - Die interne Datenbankversion nicht neuer ist als die des Servers.
--
-- Sicherheit:
-- Benötigt Mitgliedschaft in der festen Serverrolle 'sysadmin'.
-- Vorübergehende Aktivierung von xp_cmdshell wird nach der Ausführung
-- in den ursprünglichen Zustand zurückversetzt.
--
-- Einschränkungen:
-- - Funktioniert nur mit Datenbanken, die aus einer einzelnen .mdf-Datei
-- bestehen (keine zusätzlichen .ndf oder separate .ldf).
-- - Nur Laufwerksbuchstaben (z.B. D:\) werden unterstützt; UNC-Pfade
-- (\\server\share) nicht.
-- - Die .mdf-Dateien müssen den primären Datenbanknamen als Basis haben.
-- - Die Dateien müssen direkt im angegebenen Ordner liegen (keine Unterordner).
--
-- Änderungshistorie:
-- [Datum] Initiale Version (korrigiert und erweitert)
-- =====================================================================
SET NOCOUNT ON;
DECLARE @AttachFromDir nvarchar(500) = N'F:\Daten\SQL' -- Hier das Quellverzeichnis anpassen
-- Tabellen für Dateiliste und Prüfergebnisse
DECLARE @TabFileNames TABLE (FileName nvarchar(260));
DECLARE @TabFileAttribiute TABLE (attrName sql_variant, attrValue sql_variant);
-- Variablen für Cursor und Verarbeitung
DECLARE @readDirCmd nvarchar(1000);
DECLARE @Aktuell nvarchar(160);
DECLARE @dbs nvarchar(256);
DECLARE @phys_name nvarchar(520);
DECLARE @dbccstmt nvarchar(1000);
DECLARE @dbsVersionAttach INT;
DECLARE @VersionServer INT;
-- =====================================================================
-- 1. Vorbereitung: xp_cmdshell-Zustand sichern
-- =====================================================================
DECLARE @cmdshell_was_activated INT;
SELECT @cmdshell_was_activated = CAST(value_in_use AS INT)
FROM sys.configurations
WHERE name = 'xp_cmdshell';
IF @cmdshell_was_activated = 0
BEGIN
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
END
-- =====================================================================
-- 2. Dateiliste aus Verzeichnis holen
-- =====================================================================
SET @readDirCmd = N'dir /b "' + @AttachFromDir + N'"\*.mdf';
INSERT INTO @TabFileNames (FileName)
EXEC xp_cmdshell @readDirCmd;
-- Ungültige Einträge entfernen (NULL, "File Not Found", leere Zeilen)
DELETE FROM @TabFileNames
WHERE FileName IS NULL
OR FileName = 'File Not Found'
OR LTRIM(RTRIM(FileName)) = '';
-- =====================================================================
-- 3. Bereits angehängte Datenbankdateien herausfiltern
-- =====================================================================
DELETE a
FROM @TabFileNames a
INNER JOIN sys.master_files b
ON UPPER(@AttachFromDir + N'\' + a.FileName) = UPPER(b.physical_name);
-- Falls keine Dateien übrig sind, abbrechen
IF NOT EXISTS (SELECT 1 FROM @TabFileNames)
BEGIN
PRINT N'Keine neuen Dateien gefunden. Prüfen Sie das Verzeichnis: ' + @AttachFromDir;
GOTO Cleanup;
END
-- =====================================================================
-- 4. Version des Servers ermitteln
-- =====================================================================
SELECT @VersionServer = CONVERT(INT, DATABASEPROPERTYEX('master', 'version'));
-- =====================================================================
-- 5. Cursor über die verbleibenden Dateien
-- =====================================================================
DECLARE cf CURSOR LOCAL FAST_FORWARD FOR
SELECT FileName FROM @TabFileNames ORDER BY FileName;
OPEN cf;
FETCH NEXT FROM cf INTO @Aktuell;
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
SET @phys_name = @AttachFromDir + N'\' + @Aktuell;
SET @dbccstmt = N'DBCC CHECKPRIMARYFILE (' + QUOTENAME(@phys_name, '"') + N', 2)';
-- Prüfinformationen aus der MDF-Datei holen
DELETE FROM @TabFileAttribiute; -- Vorherige Daten löschen
INSERT INTO @TabFileAttribiute
EXEC (@dbccstmt);
-- Datenbanknamen extrahieren
SELECT @dbs = CONVERT(nvarchar(256), attrValue)
FROM @TabFileAttribiute
WHERE attrName = 'Database name';
-- Datenbankversion der Datei extrahieren
SELECT @dbsVersionAttach = CONVERT(INT, attrValue)
FROM @TabFileAttribiute
WHERE attrName = 'Database version';
-- Prüfen, ob Datenbank bereits existiert oder Version zu hoch ist
IF (@dbsVersionAttach > @VersionServer)
BEGIN
PRINT N'[Übersprungen] ' + @dbs + N' – Datenbankversion (' + CAST(@dbsVersionAttach AS nvarchar) +
N') ist neuer als Serverversion (' + CAST(@VersionServer AS nvarchar) + N').';
END
ELSE IF EXISTS (SELECT 1 FROM sys.databases WHERE name = @dbs)
BEGIN
PRINT N'[Übersprungen] ' + @dbs + N' – Datenbank ist bereits am Server vorhanden.';
END
ELSE
BEGIN
-- Attach mit CREATE DATABASE (modern, statt sp_attach_single_file_db)
DECLARE @attachSQL nvarchar(2000);
SET @attachSQL = N'CREATE DATABASE ' + QUOTENAME(@dbs) +
N' ON (FILENAME = ' + QUOTENAME(@phys_name, '''') + N') ' +
N'FOR ATTACH;';
EXEC sp_executesql @attachSQL;
PRINT N'[Erfolg] Datenbank "' + @dbs + N'" angehängt von Datei: ' + @Aktuell;
END
END TRY
BEGIN CATCH
PRINT N'[Fehler] Bei Datei "' + @Aktuell + N'": ' + ERROR_MESSAGE();
END CATCH
-- Temporäre Tabelle für nächsten Durchlauf leeren
DELETE FROM @TabFileAttribiute;
FETCH NEXT FROM cf INTO @Aktuell;
END
CLOSE cf;
DEALLOCATE cf;
-- =====================================================================
-- 6. Aufräumen: xp_cmdshell auf ursprünglichen Zustand zurücksetzen
-- =====================================================================
Cleanup:
IF @cmdshell_was_activated = 0
BEGIN
EXEC sp_configure 'xp_cmdshell', 0;
RECONFIGURE;
EXEC sp_configure 'show advanced options', 0;
RECONFIGURE;
END
SET NOCOUNT OFF;