tags:

views:

1221

answers:

7

I have a database table and one of the fields (not primary key) is having unique index on it. Now I want to swap values under this column for two rows. How could this be done? Two hack I know are:

  1. Delete both rows and re-insert them
  2. Update rows with some other value and swap and then update to actual value.

But I don't want to go for these as they do not seem to be the appropriate solution to the problem. Could anyone help me out?

A: 

I'm only familiar with MySQL but I don't believe there is any SQL or MySQL specific functions to do it.

Unkwntech
+1  A: 

I think you should go for solution 2. There is no 'swap' function in any SQL variant I know of.

If you need to do this regularly, I suggest solution 1, depending on how other parts of the software are using this data. You can have locking issues if you're not careful.

But in short: there is no other solution than the ones you provided.

Daan
+1  A: 

I also think that #2 is the best bet, though I would be sure to wrap it in a transaction in case something goes wrong mid-update.

An alternative (since you asked) to updating the Unique Index values with different values would be to update all of the other values in the rows to that of the other row. Doing this means that you could leave the Unique Index values alone, and in the end, you end up with the data that you want. Be careful though, in case some other table references this table in a Foreign Key relationship, that all of the relationships in the DB remain intact.

Yaakov Ellis
A: 

Assuming you know the PK of the two rows you want to update... This works in SQL Server, can't speak for other products. SQL is (supposed to be) atomic at the statement level:

CREATE TABLE testing ( cola int NOT NULL, colb CHAR(1) NOT NULL )

CREATE UNIQUE INDEX UIX_testing_a ON testing(colb)

INSERT INTO testing VALUES (1, 'b') INSERT INTO testing VALUES (2, 'a')

SELECT * FROM testing

UPDATE testing SET colb = CASE cola WHEN 1 THEN 'a' WHEN 2 THEN 'b' END WHERE cola IN (1,2)

SELECT * FROM testing

so you will go from:

cola colb

1 b 2 a

to:

cola colb

1 a 2 b

Andy Irving
This did not work for me in MySQL.
divideandconquer.se
+2  A: 

Further to Andy Irving's answer

this worked for me (on SQL Server 2005) in a similar situation where I have a composite key and I need to swap a field which is part of the unique constraint.

key: pID, LNUM rec1: 10, 0 rec2: 10, 1 rec3: 10, 2

and I need to swap LNUM so that the result is

key: pID, LNUM rec1: 10, 1 rec2: 10, 2 rec3: 10, 0

the SQL needed:

UPDATE    DOCDATA    
SET       LNUM = CASE LNUM
              WHEN 0 THEN 1
              WHEN 1 THEN 2 
              WHEN 2 THEN 0 
          END
WHERE     (pID = 10) 
  AND     (LNUM IN (0, 1, 2))
If this works, thats great cos it can be done within a single transaction
codeulike
+1  A: 

I have the same problem. Here's my proposed approach in PostgreSQL. In my case, my unique index is a sequence value, defining an explicit user-order on my rows. The user will shuffle rows around in a web-app, then submit the changes.

I'm planning to add a "before" trigger. In that trigger, whenever my unique index value is updated, I will look to see if any other row already holds my new value. If so, I will give them my old value, and effectively steal the value off them.

I'm hoping that PostgreSQL will allow me to do this shuffle in the before trigger.

I'll post back and let you know my mileage.

the.jxc
A: 

Oracle has deferred integrity checking which solves exactly this, but it is not available in either SQL Server or MySQL.

BlueRaja - Danny Pflughoeft