2009-11-19 18 views
5

Tengo una tabla regionkey:Intercambiar dos filas DB sin violar las restricciones

areaid -- primary key, int 
region -- char(4) 
locale -- char(4) 

Todo el resto de la base de datos es areaid de la carrocería exterior. En esta tabla hay un índice sobre (región, localidad) con una restricción única.

El problema es que tengo dos registros:

101 MICH DETR 
102 ILLI CHIC 

Y necesito cambiar la (región, localidad) Campos entre ellos, por lo que termino con:

101 ILLI CHIC 
102 MICH DETR 

El enfoque ingenuo no funcionará porque viola el índice único en la región y la configuración regional:

update regionkey 
    set region='ILLI', locale='CHIC' where areaid = 101; -- FAILS 
update regionkey 
    set region='MICH', locale='DETR' where areaid = 102; 

¿Cómo puedo hacer esto? ¿Hay una forma atómica para hacer el intercambio? Sugerencias?

Respuesta

8

No se puede aplazar las comprobaciones de restricciones en SQL Server a través de múltiples declaraciones (a menos que deshabilite) así que hay que evitar el conflicto o hacerlo en un comunicado

update 
    regionkey 
set 
    region= CASE areaid WHEN 101 THEN 'ILLI' ELSE 'MICH' END, 
    locale= CASE areaid WHEN 101 THEN 'CHIC' ELSE 'DETR' END 
where 
    areaid IN (101, 102); 

o, de manera más convencional (en una transacción este)

update regionkey 
    set region='AAAA', locale='BBBB' where areaid = 101; 
update regionkey 
    set region='MICH', locale='DETR' where areaid = 102; 
update regionkey 
    set region='ILLI', locale='CHIC' where areaid = 101; 

Editar: ¿Por qué no cambiar las claves, no los valores? Por lo general, logra el resultado correcto a menos que el areaid tenga algún significado

update 
    regionkey 
set 
    areaid = 203 - areaid 
where 
    areaid IN (101, 102); 
+0

Esto puede ser lo suficientemente loco como para funcionar. ¿Crees que debería envolverlo en una transacción? – Broam

+0

una sola inserción es una sola transacción implícita de todos modos – gbn

+0

Solo un poco más rápido que yo, @gbn ;-) – karlgrz

1

BEst apuesta es hacer tres actualizaciones. Actualice el primer registro a un conjunto temporal de valores, actualice el segundo registro y luego vuelva a actualizar el primer registro con los valores que desee.

0

¿Has probado el simple hecho de envolverlo en una transacción?

Entiendo que puede establecer restricciones para permitir que solo aplique la restricción al final de una transacción, pero no estoy seguro si sus restricciones están configuradas de esa manera.

+1

No existe una "restricción diferida" en SQL Server, a menos que use explícitamente DISABLE que es una declaración DDL – gbn

+0

Estoy iluminado, gracias. – Broam

0

Una sugerencia, que puede no ser el más seguro para grandes conjuntos de registros, sería establecer ambos registros a '' tanto para la región & local, y luego ejecutar dos instrucciones de actualización, uno para cada registro, así:

UPDATE 
    regionkey 
SET 
    region = ' ', 
    locale = ' ' 
WHERE 
    areaid in (101,102) 

UPDATE 
    regionkey 
SET 
    region = 'ILLI', 
    locale = 'CHIC' 
WHERE 
    areaid = 101 

UPDATE 
    regionkey 
SET 
    region = 'MICH', 
    locale = 'DETR' 
WHERE 
    areaid = 102 

Como he dicho, esto no es probablemente la forma más segura de ir, pero para establecer una pequeña de datos debería estar bien.

ACTUALIZACIÓN: Larry señaló correctamente que la primera instrucción UPDATE violará la restricción ÚNICA. Utilice esta vez para la primera actualización:

UPDATE 
    regionkey 
SET 
    region = areaid, 
    locale = areaid 
WHERE 
    areaid in (101,102) 

De esta manera cada región intermedia y la configuración regional es (o debería ser) único.

+0

Mismo problema: la ACTUALIZACIÓN inicial violará lo ÚNICO en la región y la configuración regional. –

+0

¡Tienes razón! He actualizado mi respuesta para reflejar esto. Buena captura, @Larry! – karlgrz

Cuestiones relacionadas