Sie können das Problem lösen, indem Sie zwei Cursor oder einen Cursor verwenden. Zwei Cursor machen den Code lesbarer. Ein Cursor wird effizienter.
zwei Cursor
Der folgende Code zeigt, wie zwei Cursor verwenden, um die Tabellen und Spalten iterieren.
DECLARE @tblNm VARCHAR(MAX)
DECLARE cTables CURSOR FOR
SELECT tblNm
FROM CompositeSchema
GROUP BY tblNm
ORDER BY tblNm
OPEN cTables
FETCH cTables INTO @tblNm
WHILE @@FETCH_STATUS=0
BEGIN
PRINT 'Processing table '[email protected]
-- Start of code to execute for each table
DECLARE @sqlCreateTable VARCHAR(MAX)
SET @sqlCreateTable = 'CREATE TABLE ['[email protected]+'] ('
DECLARE @colNm VARCHAR(MAX),@colTyp VARCHAR(MAX),@colLen INT,@colReq BIT,@colWarning BIT,@colUni BIT,@colComUni BIT
DECLARE @isFirst BIT
SET @isFirst = 1
DECLARE cCols CURSOR FOR
SELECT colNm,colTyp,colLen,colReq,colWarning,colUni,colComUni
FROM CompositeSchema
WHERE [email protected]
ORDER BY colComUni DESC,colNm ASC
OPEN cCols
FETCH cCols INTO @colNm,@colTyp,@colLen,@colReq,@colWarning,@colUni,@colComUni
WHILE @@FETCH_STATUS=0
BEGIN
PRINT 'Processing column ['[email protected]+'].['[email protected]+']'
-- Start of code to process each column (simplified!)
IF @isFirst=0
SET @sqlCreateTable = @sqlCreateTable+','
SET @isFirst = 0
SET @sqlCreateTable = @sqlCreateTable+'['[email protected]+'] '[email protected]
IF NOT @colLen IS NULL
SET @sqlCreateTable = @sqlCreateTable+'('+CAST(@colLen AS VARCHAR)+')'
-- End of code to process each column
FETCH cCols INTO @colNm,@colTyp,@colLen,@colReq,@colWarning,@colUni,@colComUni
END
CLOSE cCols
DEALLOCATE cCols
SET @sqlCreateTable = @sqlCreateTable+')'
PRINT @sqlCreateTable
-- EXEC(@sqlCreateTable)
-- End of code to execute for each table
FETCH cTables INTO @tblNm
END
CLOSE cTables
DEALLOCATE cTables
Ein Cursor
In diesem Fall verwenden wir einen Cursor gerade. Wir verfolgen, was die aktuelle Tabelle ist, die wir in der Variablen @currentTblNm verarbeiten. Wenn sich die Variable ändert, erstellen wir alle Spalten gleichzeitig.
DECLARE @currentTblNm VARCHAR(MAX),@sqlCreateTable VARCHAR(MAX)
SET @currentTblNm = ''
DECLARE @tblNm VARCHAR(MAX),@colNm VARCHAR(MAX),@colTyp VARCHAR(MAX),@colLen INT,@colReq BIT,@colWarning BIT,@colUni BIT,@colComUni BIT
DECLARE @isFirst BIT
SET @isFirst = 1
DECLARE cCols CURSOR FOR
SELECT tblNm,colNm,colTyp,colLen,colReq,colWarning,colUni,colComUni
FROM CompositeSchema
ORDER BY tblNm ASC,colComUni DESC,colNm ASC
OPEN cCols
FETCH cCols INTO @tblNm,@colNm,@colTyp,@colLen,@colReq,@colWarning,@colUni,@colComUni
WHILE @@FETCH_STATUS=0
BEGIN
IF @currentTblNm<>@tblNm
BEGIN
IF @sqlCreateTable<>''
BEGIN
SET @sqlCreateTable = @sqlCreateTable+')'
PRINT @sqlCreateTable
--EXEC (@sqlCreateTable)
END
SET @isFirst = 1
SET @sqlCreateTable = 'CREATE TABLE ['[email protected]+'] ('
SET @currentTblNm = @tblNm
PRINT 'Processing table ['[email protected]+']'
END
-- Start of code to process each column (simplified!)
IF @isFirst=0
SET @sqlCreateTable = @sqlCreateTable+','
SET @isFirst = 0
SET @sqlCreateTable = @sqlCreateTable+'['[email protected]+'] '[email protected]
IF NOT @colLen IS NULL
SET @sqlCreateTable = @sqlCreateTable+'('+CAST(@colLen AS VARCHAR)+')'
-- End of code to process each column
FETCH cCols INTO @tblNm,@colNm,@colTyp,@colLen,@colReq,@colWarning,@colUni,@colComUni
END
CLOSE cCols
DEALLOCATE cCols
IF @sqlCreateTable<>''
BEGIN
SET @sqlCreateTable = @sqlCreateTable+')'
PRINT @sqlCreateTable
-- EXEC(@sqlCreateTable)
END
Beide Codeteile, zwei Cursor und ein Cursor sind vereinfacht. Die Logik, um alle Einschränkungen richtig zu erstellen (wie Primärschlüssel, eindeutige Einschränkungen, Fremdschlüssel usw.), die Logik, um die Spaltendatentypen richtig zuzuordnen, und nicht zu vergessen, die Unterscheidung zwischen dem Erstellen einer neuen Tabelle und dem Ändern einer existierende Tabelle würde den Rahmen dieses Beitrags sprengen.
Erwähnenswert ist, dass Sie auch deklarativen SQL-Code mit FOR XML verwenden können, um die Tabellenstruktur zu erstellen. Dies ist möglich und würde die CREATE TABLE-Anweisungen mit einer viel besseren Leistung generieren. Aus Erfahrung weiß ich, dass dieser Code viel schwieriger zu pflegen ist und Sie möglicherweise auf die Einschränkungen von deklarativem SQL stoßen.
Was bedeuten die Werte in 'colReq colWarning colUni colComUni'? –
colReq = Darf nicht null sein colWarning = ob eine benutzerdefinierte Warnung in der Anwendung für Datenprobleme existiert, die die Validierung nicht scheitert colUni = muss eindeutig sein colComUni = hat eine Kombination von Feldern Wert, der eindeutig sein muss – MKasper
Ok, so ColReq 0 ist Nullable und 1 ist nicht Nullable. Was ist mit Warnung, Uni und den anderen Spalten? –