2009-11-19 3 views
5

Ich habe eine Tabelle regionkey:Swapping zwei DB Reihen ohne Einschränkungen zu verletzen

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

Der gesamte Rest der Datenbank ist im Ausland verkeilt AreaID. In dieser Tabelle gibt es einen Index für (Region, Gebietsschema) mit einer eindeutigen Einschränkung.

Das Problem ist, dass ich zwei Datensätze:

101 MICH DETR 
102 ILLI CHIC 

Und ich brauche die (Region, locale) Felder zwischen ihnen zu wechseln, so dass ich mit aufzuwickeln:

101 ILLI CHIC 
102 MICH DETR 

Die naiver Ansatz wird nicht funktionieren, weil sie den eindeutigen Index für Region und locale verletzt:

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

Wie kann ich das tun? Gibt es einen atomaren Weg, den Swap zu machen? Vorschläge?

Antwort

8

Sie können nicht Constraint prüft in SQL Server über mehrere Anweisungen (es sei denn, Sie deaktivieren) verschieben, so dass Sie

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); 

oder mehr konventionell (in einer Transaktion den Konflikt oder tun es in einer Erklärung vermeiden dieser)

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; 

Edit: Warum nicht Schlüssel nicht Werte tauschen? Gewöhnlich erzielt es das gesunde Ergebnis, es sei denn, Areaid hat eine Bedeutung

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

Dies kann einfach verrückt genug sein, um zu arbeiten. Glaubst du, er sollte es in eine Transaktion einpacken? – Broam

+0

eine einzige Einfügung ist sowieso eine einzige implizite Transaktion – gbn

+0

Nur ein bisschen schneller als ich, @gbn ;-) – karlgrz

1

BEst Wette ist, drei Updates zu machen. Aktualisieren Sie den ersten Datensatz in einen temporären Satz von Werten, aktualisieren Sie den zweiten Datensatz und aktualisieren Sie dann den ersten Datensatz erneut auf die gewünschten Werte.

0

Haben Sie den einfachen Akt des Einwickelns es in einer Transaktion versucht?

Ich verstehe, dass Sie Constraints einrichten können, damit es nur die Einschränkung am Ende einer Transaktion erzwingt, aber ich bin unsicher, ob Ihre Constraints auf diese Weise eingerichtet sind.

+1

Es gibt keine "Defer Constraint" in SQL Server, es sei denn, Sie verwenden explizit DISABLE, die eine DDL-Anweisung ist – gbn

+0

Ich bin erleuchtet, danke. – Broam

0

Ein Vorschlag, der nicht die sichersten für großen Datensätze sein kann, wäre beid Aufzeichnungen setzen ‚auf‘ für beide Region & locale, und dann zwei Update-Anweisungen ausführen, einen für jeden Datensatz, etwa so:

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 

Wie ich schon sagte, ist dies wahrscheinlich nicht der sicherste Weg zu gehen, aber für einen kleinen Datensatz sollte es in Ordnung sein.

UPDATE: Larry wies richtig darauf hin, dass die erste UPDATE-Anweisung die UNIQUE-Einschränkung verletzen wird. Verwenden Sie stattdessen das erste UPDATE:

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

diese Weise kann jeder Zwischenbereich und locale ist (oder sein sollte) einzigartig.

+0

Gleiches Problem - das anfängliche UPDATE verletzt die UNIQUEness für Region, Gebietsschema. –

+0

Sie sind richtig !!! Ich habe meine Antwort aktualisiert, um dies zu berücksichtigen. Guter Fang, @Larry! – karlgrz

Verwandte Themen