· 8 years ago · Aug 30, 2018, 06:52 PM
1IF OBJECT_ID('tempdb..#PrintMax', 'P') IS NOT NULL DROP PROCEDURE #PrintMax;
2GO
3CREATE PROCEDURE #PrintMax
4(
5 @iInput NVARCHAR(MAX)
6)
7AS
8BEGIN
9 -- nothing we can do with null data
10 IF (@iInput IS NULL) BEGIN
11 RETURN;
12 END;
13
14 -- This procedure was created to properly print
15 -- nvarchar(max) since the print statement can
16 -- only handle NVARCHAR(4000), we break the
17 -- input down into 4000 byte blocks and print
18 -- upto the last linebreak before the 4000 byte cutoff
19 DECLARE @ReversedData NVARCHAR(MAX)
20 ,@LineBreakIndex INT
21 ,@SearchLength INT;
22
23 -- if the search length is less than the first occurance
24 -- of a line break, the data will be printed with a line break
25 -- at the SearchLength position even though there should not be
26 -- a break in the data there.
27 SET @SearchLength = 4000;
28
29 -- only loop while the input is greater than the search length
30 WHILE (LEN(@iInput) > @SearchLength) BEGIN
31 -- obtain and reverse the input upto the search length
32 SET @ReversedData = LEFT(@iInput, @SearchLength) COLLATE database_default;
33 SET @ReversedData = REVERSE(@ReversedData) COLLATE database_default;
34
35 -- determine the position of the first line break for this piece of data
36 SET @LineBreakIndex = CHARINDEX(CHAR(10) + CHAR(13), @ReversedData COLLATE database_default);
37
38 -- print the input only showing data upto the line break
39 -- the original linebreak will not be displayed
40 PRINT LEFT(@iInput, @SearchLength - @LineBreakIndex + 1);
41
42 -- resize the input removing the data that was displayed and the line break.
43 SET @iInput = RIGHT(@iInput COLLATE database_default, LEN(@iInput) - @SearchLength + @LineBreakIndex - 1);
44 END;
45
46 -- if there is any data remaining, print it
47 IF (LEN(@iInput) > 0) BEGIN
48 PRINT @iInput;
49 END;
50END;
51GO
52DECLARE
53-- Parameters:
54 @SourceTableName SYSNAME = 'dbo.tbl_contacts',
55 @ChunkIntervalForSingleColumnPK INT = 1000,
56 @OperationDeltaColumn SYSNAME = 'Operation',
57 @PrecedenceDeltaColumn SYSNAME = 'Precedence',
58 @RowRankDeltaColumn SYSNAME = 'RowRank'
59
60DECLARE
61 @SourceTableID INT = OBJECT_ID(@SourceTableName),
62 @CleanSourceTableName SYSNAME = OBJECT_NAME(OBJECT_ID(@SourceTableName))
63
64IF @SourceTableID IS NULL
65BEGIN
66 RAISERROR(N'Source Table %s not found!',16,1,@SourceTableName);
67 GOTO Quit;
68END
69ELSE
70 SET @SourceTableName = QUOTENAME(OBJECT_SCHEMA_NAME(@SourceTableID)) + N'.' + QUOTENAME(OBJECT_NAME(@SourceTableID))
71
72-- Local variables:
73DECLARE
74 @NewTableName SYSNAME = QUOTENAME(OBJECT_SCHEMA_NAME(@SourceTableID)) + N'.' + QUOTENAME(@CleanSourceTableName + '_NEW'),
75 @DeltaTableName SYSNAME = QUOTENAME(OBJECT_SCHEMA_NAME(@SourceTableID)) + N'.' + QUOTENAME(@CleanSourceTableName + '_DELTA'),
76 @OldTableName SYSNAME = QUOTENAME(OBJECT_SCHEMA_NAME(@SourceTableID)) + N'.' + QUOTENAME(@CleanSourceTableName + N'_OLD')
77
78DECLARE
79 @CMD NVARCHAR(MAX),
80 @PKindex NVARCHAR(MAX),
81 @PKcolumnDefinitions NVARCHAR(MAX),
82 @PKcolumnList NVARCHAR(MAX),
83 @PKjoin NVARCHAR(MAX),
84 @PKcolumnCount INT
85
86-- Validations
87
88IF OBJECT_ID(@NewTableName) IS NOT NULL
89BEGIN
90 RAISERROR(N'-- NEW table %s already exists!', 0, 1, @NewTableName);
91 --GOTO Quit;
92END
93IF OBJECT_ID(@DeltaTableName) IS NOT NULL
94BEGIN
95 RAISERROR(N'-- DELTA table %s already exists!', 0, 1, @DeltaTableName);
96 --GOTO Quit;
97END
98IF OBJECT_ID(@OldTableName) IS NOT NULL
99BEGIN
100 RAISERROR(N'OLD table %s already exists!', 16, 1, @OldTableName);
101 GOTO Quit;
102END
103IF EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(@SourceTableName) AND name IN (@OperationDeltaColumn, @PrecedenceDeltaColumn, @RowRankDeltaColumn))
104BEGIN
105 RAISERROR(N'One or more of the following columns already exist in %s: @OperationDeltaColumn, @PrecedenceDeltaColumn, @RowRankDeltaColumn', 16, 1, @SourceTableName);
106 GOTO Quit;
107END
108
109
110SELECT
111 @PKindex = N' PRIMARY KEY ' + pk.type_desc COLLATE database_default + N' ('
112 + STUFF(
113 (SELECT ', ' + QUOTENAME(c.name) COLLATE database_default + ' ' + CASE is_descending_key WHEN 1 THEN 'DESC' ELSE 'ASC' END FROM sys.index_columns AS ic INNER JOIN sys.columns AS c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE ic.is_included_column = 0 AND ic.object_id = pk.object_id AND ic.index_id = pk.index_id ORDER BY ic.key_ordinal ASC FOR XML PATH(''))
114 , 1,2,'')
115 + N')
116 WITH (FILLFACTOR = ' + CONVERT(nvarchar(max), ISNULL(NULLIF(pk.fill_factor,0),100))
117 + N', ALLOW_ROW_LOCKS = ' + CASE pk.allow_row_locks WHEN 1 THEN 'ON' ELSE 'OFF' END
118 + N', ALLOW_PAGE_LOCKS = ' + CASE pk.allow_page_locks WHEN 1 THEN 'ON' ELSE 'OFF' END
119 + N', IGNORE_DUP_KEY = ' + CASE pk.ignore_dup_key WHEN 1 THEN 'ON' ELSE 'OFF' END
120 + N', PAD_INDEX = ' + CASE pk.is_padded WHEN 1 THEN 'ON' ELSE 'OFF' END
121 + N')
122 ON ' + QUOTENAME(ds.name) COLLATE database_default
123FROM sys.indexes AS pk
124INNER JOIN sys.data_spaces AS ds ON pk.data_space_id = ds.data_space_id
125WHERE object_id = @SourceTableID
126AND is_primary_key = 1
127
128
129-- 1. Create empty staging table
130
131IF OBJECT_ID(@NewTableName) IS NULL
132BEGIN
133 RAISERROR(N'-- Creating empty %s...',0,1,@NewTableName) WITH NOWAIT;
134
135 SET @CMD = N'
136 SELECT * INTO ' + @NewTableName + N'
137 FROM ' + @SourceTableName + N'
138 WHERE 1=0;'
139
140 -- 2. Create clustered PK on staging table
141
142 SELECT @CMD = @CMD + N'
143
144 ALTER TABLE ' + @NewTableName
145 + N' ADD CONSTRAINT ' + QUOTENAME(pk.name + '_NEW') COLLATE database_default
146 FROM sys.indexes AS pk
147 INNER JOIN sys.data_spaces AS ds ON pk.data_space_id = ds.data_space_id
148 WHERE object_id = @SourceTableID
149 AND is_primary_key = 1
150
151 PRINT @CMD + @PKindex
152
153END
154
155-- Parse PK columns
156SELECT
157 @PKcolumnDefinitions = ISNULL(@PKcolumnDefinitions + N', ', N'') + QUOTENAME(c.name) COLLATE database_default + N' ' + t.name + N' ' + CASE c.is_nullable WHEN 1 THEN 'NULL' ELSE 'NOT NULL' END
158 ,@PKcolumnList = ISNULL(@PKcolumnList + N', ', N'') + QUOTENAME(c.name) COLLATE database_default
159 ,@PKjoin = ISNULL(@PKjoin + N'
160 AND ', N'') + N'Trgt.' + QUOTENAME(c.name) COLLATE database_default + N' = Src.' + QUOTENAME(c.name) COLLATE database_default
161 ,@PKcolumnCount = ISNULL(@PKcolumnCount,0) + 1
162FROM sys.indexes AS pk
163INNER JOIN sys.index_columns AS ic
164ON ic.is_included_column = 0
165AND ic.object_id = pk.object_id
166AND ic.index_id = pk.index_id
167INNER JOIN sys.columns AS c
168ON ic.object_id = c.object_id
169AND ic.column_id = c.column_id
170INNER JOIN sys.types AS t
171ON c.system_type_id = t.system_type_id
172AND c.user_type_id = t.user_type_id
173WHERE pk.object_id = @SourceTableID
174AND pk.is_primary_key = 1
175ORDER BY ic.key_ordinal ASC
176
177-- 3. Create empty table tbl_contacts_DELTA
178
179IF OBJECT_ID(@DeltaTableName) IS NULL
180BEGIN
181 RAISERROR(N'-- Creating tbl_contacts_DELTA...',0,1) WITH NOWAIT;
182
183 SET @CMD = N'
184 CREATE TABLE ' + @DeltaTableName + N'
185 (
186 ' + @PKcolumnDefinitions + N',
187 ' + QUOTENAME(@OperationDeltaColumn) + N' CHAR(1) NOT NULL,
188 ' + @PKindex + N'
189 );'
190
191 EXEC #PrintMax @CMD
192END
193
194-- 4. Create AFTER trigger on tbl_contacts
195SET @CMD = N'CREATE TRIGGER dbo.TR_DELTA ON ' + @SourceTableName + N'
196AFTER INSERT,DELETE,UPDATE
197AS
198 SET NOCOUNT ON;
199
200 ; WITH Src AS
201 (
202 SELECT *, ' + QUOTENAME(@RowRankDeltaColumn) + N' = ROW_NUMBER() OVER (PARTITION BY ' + @PKcolumnList + N' ORDER BY ' + QUOTENAME(@PrecedenceDeltaColumn) + N' ASC)
203 FROM
204 (
205 SELECT ' + @PKcolumnList + N', ''D'' AS ' + QUOTENAME(@OperationDeltaColumn) + N', 1 AS ' + QUOTENAME(@PrecedenceDeltaColumn) + N'
206 FROM deleted
207 UNION ALL
208 SELECT ' + @PKcolumnList + N', ''I'' AS ' + QUOTENAME(@OperationDeltaColumn) + N', 0 AS ' + QUOTENAME(@PrecedenceDeltaColumn) + N'
209 FROM inserted
210 ) AS d
211 )
212 MERGE INTO ' + @DeltaTableName + N' AS Trgt
213 USING
214 (
215 SELECT *
216 FROM Src
217 WHERE ' + QUOTENAME(@RowRankDeltaColumn) + N' = 1 -- In case of update, give precendence to the inserted row
218 ) AS Src
219 ON
220 ' + @PKjoin + N'
221 WHEN MATCHED AND Trgt.' + QUOTENAME(@OperationDeltaColumn) + N' <> Src.' + QUOTENAME(@OperationDeltaColumn) + N' THEN
222 UPDATE SET ' + QUOTENAME(@OperationDeltaColumn) + N' = Src.' + QUOTENAME(@OperationDeltaColumn) + N'
223 WHEN NOT MATCHED BY TARGET THEN
224 INSERT (' + @PKcolumnList + N')
225 VALUES (' + @PKcolumnList + N')
226 ;'
227
228PRINT 'GO'
229
230EXEC #PrintMax @CMD
231
232PRINT 'GO'
233
234
235-- 5. Migrate table by chunks
236DECLARE @PKtype NVARCHAR(MAX), @PKisIdentity BIT, @AllColumnsList NVARCHAR(MAX), @AllColumnsUpdateSet NVARCHAR(MAX)
237
238SELECT @AllColumnsList = ISNULL(@AllColumnsList + N', ', N'') + QUOTENAME(c.name) COLLATE database_default
239, @AllColumnsUpdateSet = CASE WHEN ispk.cnt = 0 THEN ISNULL(@AllColumnsUpdateSet + N',
240 ', N'') + QUOTENAME(c.name) COLLATE database_default + N' = Src.' + QUOTENAME(c.name) COLLATE database_default
241 ELSE @AllColumnsUpdateSet END
242FROM sys.columns AS c
243OUTER APPLY
244(
245 SELECT cnt = COUNT(*) FROM sys.indexes AS pk INNER JOIN sys.index_columns AS ic ON pk.object_id = ic.object_id AND pk.index_id = ic.index_id WHERE pk.is_primary_key = 1 AND pk.object_id = c.object_id AND ic.column_id = c.column_id
246) AS ispk
247WHERE c.object_id = @SourceTableID
248
249IF @PKcolumnCount = 1
250BEGIN
251
252 SELECT
253 @PKtype = t.name
254 ,@PKisIdentity = c.is_identity
255 FROM sys.indexes AS pk
256 INNER JOIN sys.index_columns AS ic
257 ON ic.is_included_column = 0
258 AND ic.object_id = pk.object_id
259 AND ic.index_id = pk.index_id
260 INNER JOIN sys.columns AS c
261 ON ic.object_id = c.object_id
262 AND ic.column_id = c.column_id
263 INNER JOIN sys.types AS t
264 ON c.system_type_id = t.system_type_id
265 AND c.user_type_id = t.user_type_id
266 WHERE pk.object_id = @SourceTableID
267 AND pk.is_primary_key = 1
268
269 SET @CMD = N'
270SET NOCOUNT ON;
271DECLARE @ChunkStart ' + @PKtype + N', @ChunkEnd ' + @PKtype + N', @ChunkInterval INT = ' + CONVERT(nvarchar(max), @ChunkIntervalForSingleColumnPK) + N'
272
273SELECT @ChunkStart = MIN(' + @PKcolumnList + N'), @ChunkEnd = MAX(' + @PKcolumnList + N')
274FROM ' + @SourceTableName + N' WITH(NOLOCK)
275
276RAISERROR(N''Starting to copy data into ' + @NewTableName + N': %d to %d.'',0,1,@ChunkStart, @ChunkEnd) WITH NOWAIT;
277
278' + CASE WHEN @PKisIdentity = 1 THEN N'SET IDENTITY_INSERT ' + @NewTableName + N' ON;' ELSE N'' END + N'
279
280WHILE @ChunkStart <= @ChunkEnd
281BEGIN
282 INSERT INTO ' + @NewTableName + CASE WHEN @PKisIdentity = 1 THEN N'
283 (' + @AllColumnsList + N')' ELSE N'' END + N'
284 SELECT
285 ' + CASE WHEN @PKisIdentity = 1 THEN @AllColumnsList ELSE N'*' END + N'
286 FROM ' + @SourceTableName + N' WITH(NOLOCK)
287 WHERE ' + @PKcolumnList + N' >= @ChunkStart
288 AND ' + @PKcolumnList + N' < @ChunkStart + @ChunkInterval
289 AND ' + @PKcolumnList + N' <= @ChunkEnd
290
291 SET @ChunkStart = @ChunkStart + @ChunkInterval
292END
293
294' + CASE WHEN @PKisIdentity = 1 THEN N'SET IDENTITY_INSERT ' + @NewTableName + N' OFF;' ELSE N'' END + N'
295
296GO'
297END
298ELSE
299BEGIN
300 DECLARE
301 @PK2columnDefinitions NVARCHAR(MAX),
302 @PK2columnList NVARCHAR(MAX),
303 @PK2variableDefinitions NVARCHAR(MAX),
304 @PK2variableList NVARCHAR(MAX),
305 @PK2variableJoin NVARCHAR(MAX)
306
307 SELECT
308 @PK2columnDefinitions = ISNULL(@PK2columnDefinitions + N', ', N'') + QUOTENAME(c.name) COLLATE database_default + N' ' + t.name + N' ' + CASE c.is_nullable WHEN 1 THEN 'NULL' ELSE 'NOT NULL' END
309 ,@PK2variableDefinitions = ISNULL(@PK2variableDefinitions + N', ', N'') + N'@pk' + CONVERT(nvarchar(max), ic.key_ordinal) +N' ' + t.name
310 ,@PK2columnList = ISNULL(@PK2columnList + N', ', N'') + QUOTENAME(c.name) COLLATE database_default
311 ,@PK2variableList = ISNULL(@PK2variableList + N', ', N'') + N'@pk' + CONVERT(nvarchar(max), ic.key_ordinal)
312 ,@PK2variableJoin = ISNULL(@PK2variableJoin + N'
313 AND ', N'') + QUOTENAME(c.name) COLLATE database_default + N' = @pk' + CONVERT(nvarchar(max), ic.key_ordinal)
314 FROM sys.indexes AS pk
315 INNER JOIN sys.index_columns AS ic
316 ON ic.is_included_column = 0
317 AND ic.object_id = pk.object_id
318 AND ic.index_id = pk.index_id
319 INNER JOIN sys.columns AS c
320 ON ic.object_id = c.object_id
321 AND ic.column_id = c.column_id
322 INNER JOIN sys.types AS t
323 ON c.system_type_id = t.system_type_id
324 AND c.user_type_id = t.user_type_id
325 WHERE pk.object_id = @SourceTableID
326 AND pk.is_primary_key = 1
327 AND ic.key_ordinal < (SELECT MAX(key_ordinal) FROM sys.index_columns AS ic2 WHERE ic2.is_included_column = 0 AND ic2.object_id = pk.object_id AND ic2.index_id = pk.index_id)
328 ORDER BY ic.key_ordinal ASC
329
330 SET @CMD = N'
331SET NOCOUNT ON;
332DECLARE @Chunks AS TABLE (' + @PK2columnDefinitions + N');
333
334INSERT INTO @Chunks
335SELECT ' + @PK2columnList + N'
336FROM ' + @SourceTableName + N' WITH(NOLOCK)
337GROUP BY ' + @PK2columnList + N'
338
339RAISERROR(N''Starting to copy data into ' + @NewTableName + N'. %d permutations in total.'',0,1,@@ROWCOUNT) WITH NOWAIT;
340
341DECLARE ' + @PK2variableDefinitions + N'
342
343DECLARE Chunks CURSOR LOCAL FAST_FORWARD FOR
344SELECT ' + @PK2columnList + N' FROM @Chunks
345
346OPEN Chunks
347FETCH NEXT FROM Chunks INTO ' + @PK2variableList + N'
348
349WHILE @@FETCH_STATUS = 0
350BEGIN
351 INSERT INTO ' + @NewTableName + N'
352 SELECT
353 *
354 FROM ' + @SourceTableName + N' WITH(NOLOCK)
355 WHERE ' + @PK2variableJoin + N'
356
357 FETCH NEXT FROM Chunks INTO ' + @PK2variableList + N'
358END
359
360CLOSE Chunks
361DEALLOCATE Chunks
362GO'
363
364END
365
366EXEC #PrintMax @CMD
367
368-- 6. Create non-clustered indexes on tbl_contacts_NEW
369
370SET @CMD = N''
371RAISERROR(N'-- Creating non-clustered indexes on %s...',0,1, @NewTableName) WITH NOWAIT;
372
373 SELECT @CMD = @CMD + N'
374
375 CREATE NONCLUSTERED INDEX ' + QUOTENAME(i.name) + N' ON ' + @NewTableName + N'
376 ('
377 + STUFF(
378 (SELECT ', ' + QUOTENAME(c.name) COLLATE database_default + ' ' + CASE is_descending_key WHEN 1 THEN 'DESC' ELSE 'ASC' END FROM sys.index_columns AS ic INNER JOIN sys.columns AS c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE ic.is_included_column = 0 AND ic.object_id = i.object_id AND ic.index_id = i.index_id ORDER BY ic.key_ordinal ASC FOR XML PATH(''))
379 , 1,2,'')
380 + N') ' + ISNULL(N'
381 INCLUDE (' +
382 NULLIF(STUFF(
383 (SELECT ', ' + QUOTENAME(c.name) COLLATE database_default FROM sys.index_columns AS ic INNER JOIN sys.columns AS c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE ic.is_included_column = 1 AND ic.object_id = i.object_id AND ic.index_id = i.index_id ORDER BY ic.key_ordinal ASC FOR XML PATH(''))
384 , 1,2,''), N'')
385 + N')'
386 , N'') + N'
387 WITH (FILLFACTOR = ' + CONVERT(nvarchar(max), ISNULL(NULLIF(i.fill_factor,0),100))
388 + N', ALLOW_ROW_LOCKS = ' + CASE i.allow_row_locks WHEN 1 THEN 'ON' ELSE 'OFF' END
389 + N', ALLOW_PAGE_LOCKS = ' + CASE i.allow_page_locks WHEN 1 THEN 'ON' ELSE 'OFF' END
390 + N', IGNORE_DUP_KEY = ' + CASE i.ignore_dup_key WHEN 1 THEN 'ON' ELSE 'OFF' END
391 + N', PAD_INDEX = ' + CASE i.is_padded WHEN 1 THEN 'ON' ELSE 'OFF' END
392 + N')
393 ON ' + QUOTENAME(ds.name) COLLATE database_default + N';'
394 FROM sys.indexes AS i
395 INNER JOIN sys.data_spaces AS ds ON i.data_space_id = ds.data_space_id
396 WHERE object_id = @SourceTableID
397 AND i.is_primary_key = 0
398 AND i.index_id > 1 -- nonclustered
399
400EXEC #PrintMax @CMD
401
402PRINT 'GO'
403RAISERROR(N'-- 7. First merge from the Delta table onto %s',0,1,@NewTableName);
404
405SET @CMD = N'
406DECLARE @RCount INT
407SELECT @RCount = COUNT(*) FROM ' + @DeltaTableName + N' WITH(NOLOCK);
408
409RAISERROR(N''Merging %d rows from Delta to New...'',0,1,@RCount) WITH NOWAIT;
410
411; WITH Trgt AS
412(
413 SELECT * FROM {@NewTableName} WITH(TABLOCKX)
414), Delta AS
415(
416 SELECT Src.*, Trgt.' + QUOTENAME(@OperationDeltaColumn) + N'
417 FROM {@SourceTableName} AS Src
418 INNER JOIN ' + @DeltaTableName + N' AS Trgt
419 ON
420 ' + @PKjoin + N'
421)
422MERGE INTO Trgt
423USING Delta AS Src
424ON
425 ' + @PKjoin + ISNULL(N'
426WHEN MATCHED THEN
427 UPDATE SET
428 ' + @AllColumnsUpdateSet, N'') + N'
429WHEN MATCHED AND Src.' + QUOTENAME(@OperationDeltaColumn) + N' = ''D'' THEN
430 DELETE
431WHEN NOT MATCHED BY TARGET AND Src.' + QUOTENAME(@OperationDeltaColumn) + N' = ''I'' THEN
432 INSERT (' + @AllColumnsList + N')
433 VALUES (' + @AllColumnsList + N')
434;
435RAISERROR(N''Merged %d rows.'',0,1, @@ROWCOUNT) WITH NOWAIT;
436'
437DECLARE @CMD_Temp NVARCHAR(MAX)
438SET @CMD_Temp = REPLACE(REPLACE(@CMD, N'{@NewTableName}',@NewTableName), N'{@SourceTableName}', @SourceTableName)
439
440EXEC #PrintMax @CMD_Temp
441
442SET @CMD = N'
443GO
444/****************************************************************/
445
446/********* !!! CRITICAL BLOCKING SECTION BEGINS NOW !!! *********/
447
448/****************************************************************/
449
450-- 8. Rename tables
451
452RAISERROR(N''Renaming tables...'',0,1) WITH NOWAIT;
453
454BEGIN TRAN
455SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
456
457EXEC sp_rename ''' + @SourceTableName + N''', ''' + @CleanSourceTableName + N'_OLD''
458EXEC sp_rename ''' + @NewTableName + N''', ''' + @CleanSourceTableName + N'''
459GO
460
461-- 9. Apply changes from the Delta table onto the new table
462' + REPLACE(REPLACE(@CMD, N'{@NewTableName}',@SourceTableName), N'{@SourceTableName}', @OldTableName) + N'
463
464COMMIT TRAN
465
466RAISERROR(N''Done. You can drop the tables ' + @DeltaTableName + N' and ' + @OldTableName + N'.'',0,1) WITH NOWAIT;
467GO
468'
469
470EXEC #PrintMax @CMD
471
472Quit:
473GO
474IF OBJECT_ID('tempdb..#PrintMax', 'P') IS NOT NULL DROP PROCEDURE #PrintMax;