¿Cómo puedo alterar una clave primaria existente en SQL Azure?


25

Quiero modificar una clave primaria existente en una tabla SQL Azure.
Actualmente tiene una columna y quiero agregar otra.

Ahora, en SQL Server 2008 esto fue pan comido, solo lo hice en SSMS, poof. Hecho. Así es como se ve la PK si la escribo desde SQL Server:

ALTER TABLE [dbo].[Friend] ADD  CONSTRAINT [PK_Friend] PRIMARY KEY CLUSTERED 
(
  [UserId] ASC,
  [Id] ASC
)

Sin embargo, en SQL Azure, cuando intento ejecutar lo anterior, por supuesto fallará:

Table 'Friend' already has a primary key defined on it.

Bien, entonces trato de soltar la llave:

Tables without a clustered index are not supported in this version of SQL Server. Please create a clustered index and try again.

Ok, entonces trato de crear un índice agrupado temporal para descartar la PK:

CREATE CLUSTERED INDEX IX_Test ON [Friend] ([UserId],[Id])

Lo que resulta en: Cannot create more than one clustered index on table 'Friend'. Drop the existing clustered index 'PK_Friend' before creating another.

Genial, un momento catch22.

¿Cómo agrego la columna UserId a mi PK existente?


Respuestas:


34

Nota: a partir de Azure SQL Database v12, estas restricciones ya no se aplican.

El no existe como un 'índice primario'. Existe una 'clave primaria' y también existe un 'índice agrupado'. Conceptos distintos, a menudo confundidos. Con esta distinción en mente, volvamos a la pregunta:

Q1) ¿Se puede modificar el índice agrupado en una tabla SQL Azure?
A: si. Uso WITH (DROP_EXISTING=ON):

create table Friend (
    UserId int not null,
    Id int not null);
go  
create clustered index cdxFriend on Friend (UserId, Id);
go
create clustered index cdxFriend on Friend (Id, UserId) with (drop_existing=on);
go

P2) ¿Se puede modificar el índice agrupado de una tabla que tiene una restricción de clave primaria?
R: Sí, igual que el anterior, siempre que la restricción de clave principal no se aplique a través del índice agrupado:

create table Friend (
    UserId int not null,
    Id int not null identity(1,1),
    constraint pk_Friend primary key nonclustered (Id));
create clustered index cdxFriend on Friend (UserId, Id);
go
create clustered index cdxFriend on Friend (Id, UserId) with (drop_existing=on);
go

P3) ¿Se puede modificar la restricción de clave principal de una tabla?
R: Sí, siempre que la restricción primaria no se aplique a través del índice agrupado:

create table Friend (
    UserId int not null,
    Id int not null identity(1,1),
    constraint pk_Friend primary key nonclustered (Id));
go
create clustered index cdxFriend on Friend (UserId, Id);
go
alter table Friend drop constraint pk_Friend;
alter table Friend add constraint pk_Friend primary key nonclustered (UserId)
go

P4) ¿Se puede modificar la clave primaria de una tabla cuando se aplica a través del índice agrupado?
A: Sí, si la tabla nunca tuvo filas:

create table Friend (
    UserId int not null,
    Id int not null identity(1,1),
    constraint pk_Friend primary key clustered (UserId, Id));
go
alter table Friend drop constraint pk_Friend;
alter table Friend add constraint pk_Friend primary key clustered (Id, UserId)
go

P5) ¿Se puede modificar la clave primaria de una tabla cuando se aplica a través del índice agrupado si la tabla está llena?
R: No. Cualquier operación que convierta un índice agrupado poblado en un montón se bloqueará en SQL Azure, incluso si la tabla está vacía :

create table Friend (
    UserId int not null,
    Id int not null identity(1,1),
    constraint pk_Friend primary key clustered (UserId, Id));
go
insert into Friend (UserId) values (1);
delete from Friend;
go
alter table Friend drop constraint pk_Friend;

Como nota al margen: la restricción se puede modificar si la tabla se trunca .

La solución alternativa para cambiar la restricción PK de una tabla poblada es hacer el viejo sp_renametruco:

create table Friend (
    UserId int not null,
    Id int not null identity(1,1),
    constraint pk_Friend primary key clustered (UserId, Id));
go
insert into Friend (UserId) values (1);
go

create table FriendNew (
    UserId int not null,
    Id int not null identity(1,1),
    constraint pk_Friend_New primary key clustered (Id, UserId));
go

set identity_insert FriendNew on;
insert into FriendNew (UserId, Id) 
select UserId, Id
from Friend;
set identity_insert FriendNew off;
go

begin transaction
exec sp_rename 'Friend', 'FriendOld';
exec sp_rename 'FriendNew', 'Friend';
commit;
go

sp_help 'Friend';

El sp_renameenfoque tiene algunos problemas, lo más importante es que los permisos en la tabla no se transfieren durante el cambio de nombre, así como las restricciones de clave externa.


A1-A4 no hay respuestas en mi caso. A5 hizo el truco, aunque mi ID no es una columna de identidad.
Magnus

¡la solución de sp_rename fue útil!
Justin
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.