简体   繁体   中英

How to convert all primary keys from clustered to nonclustered in SQL Server

I have a large database with uniqueidentifier clustered primary key on every table of it. I want to remove clustered indexes from primary keys and put it on an identity column in every table.

When I want to remove clustered indexes, primary key will be removed too. So I have to create primary keys, again. the script I have wrote doesn't work. please help me

------------drop all clustered primary keys and add nonclustered primary keys-------
DECLARE @table NVARCHAR(512), @tablename NVARCHAR(512),
        @sql NVARCHAR(MAX), @sql2 NVARCHAR(MAX), @sql3 NVARCHAR(MAX), 
        @column NVARCHAR(MAX);

SELECT name As 'Table'
INTO #Indexes
FROM sys.tables 
WHERE name like 'webware%'

WHILE (SELECT COUNT(*) FROM #Indexes) > 0
BEGIN
    SET @table = (SELECT TOP 1 [Table] FROM #Indexes)

    SET @column = (SELECT c.name
                   FROM sys.tables t
                   INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
                   INNER JOIN sys.indexes i ON i.object_id = t.object_id
                   INNER JOIN sys.index_columns ic ON ic.object_id = t.object_id
                   INNER JOIN sys.columns c ON c.object_id = t.object_id 
                                            AND ic.column_id = c.column_id
                   WHERE i.is_primary_key = 1 
                     AND t.name = @table)

    DECLARE @indexname NVARCHAR(512);

    SET @indexname = (SELECT i.name
                      FROM sys.tables t
                      INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
                      INNER JOIN sys.indexes i ON i.object_id = t.object_id
                      INNER JOIN sys.index_columns ic ON ic.object_id = t.object_id
                      INNER JOIN sys.columns c ON c.object_id = t.object_id 
                                               AND ic.column_id = c.column_id
                      WHERE i.is_primary_key = 1 
                        AND t.name = @table)

   SET @sql = 'ALTER TABLE ' + @table + ' DROP CONSTRAINT ' + @indexname

   SET @sql2 = 'DROP INDEX ' +  @indexname + ' ON ' + @table

   SET @sql3 ='ALTER TABLE ' + @table + ' ADD CONSTRAINT ' + @indexname+ ' PRIMARY KEY NONCLUSTERED(' + @column +')'

   EXEC (@sql);
   EXEC (@sql2);
   EXEC (@sql3);

   DELETE FROM #Indexes WHERE [Table] = @table;
END 

DROP TABLE #Indexes

The main problem is that while a primary key is both a constraint and an index, it is an index that is created via the constraint. Meaning, you create and drop via CONSTRAINT only. Once you drop the constraint, the index will be gone. So, remove SET @sql2 and the EXEC (@sql2); .

Please keep in mind that if you have any foreign keys defined that reference any of these primary keys, those will have to be dropped first and then re-created after this particular operation completes.

You can also save some query complexity by assigning both @column and @indexname variables at the same time:

SELECT @column = c.name,
       @indexname = i.name
FROM sys.tables t
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.indexes i ON i.object_id = t.object_id
INNER JOIN sys.index_columns ic ON ic.object_id = t.object_id
INNER JOIN sys.columns c ON c.object_id = t.object_id 
                       AND ic.column_id = c.column_id
WHERE i.is_primary_key = 1 
AND t.name = @table;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM