Domanda

Ho una tabella di database e uno dei campi (non chiave primaria), ha un indice univoco su di esso.Ora voglio scambiare con i valori in questa colonna per due righe.Come potrebbe essere fatto?Due hack che conosco sono:

  1. Eliminare righe e re-inserimento.
  2. Aggiornamento delle righe con qualche altro valore e la swap e poi aggiornare al valore effettivo.

Ma io non voglio andare per questi come essi non sembrano essere la soluzione adeguata al problema.Qualcuno potrebbe aiutarmi?

È stato utile?

Soluzione

Penso che si dovrebbe andare per la soluzione 2.Non c'e 'swap' funzione in SQL variante conosco.

Se avete bisogno di fare questo regolarmente, suggerisco la soluzione 1, a seconda di come le altre parti del software sono l'utilizzo di questi dati.Si può avere problemi di blocco, se non stai attento.

Ma in breve:non c'è altra soluzione oltre a quelli che hai fornito.

Altri suggerimenti

La parola magica è RIMANDABILE qui:

DROP TABLE ztable CASCADE;
CREATE TABLE ztable
    ( id integer NOT NULL PRIMARY KEY
    , payload varchar
    );
INSERT INTO ztable(id,payload) VALUES (1,'one' ), (2,'two' ), (3,'three' );
SELECT * FROM ztable;


    -- This works, because there is no constraint
UPDATE ztable t1
SET payload=t2.payload
FROM ztable t2
WHERE t1.id IN (2,3)
AND t2.id IN (2,3)
AND t1.id <> t2.id
    ;
SELECT * FROM ztable;

ALTER TABLE ztable ADD CONSTRAINT OMG_WTF UNIQUE (payload)
    DEFERRABLE INITIALLY DEFERRED
    ;

    -- This should also work, because the constraint 
    -- is deferred until "commit time"
UPDATE ztable t1
SET payload=t2.payload
FROM ztable t2
WHERE t1.id IN (2,3)
AND t2.id IN (2,3)
AND t1.id <> t2.id
    ;
SELECT * FROM ztable;

RISULTATO:

DROP TABLE
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "ztable_pkey" for table "ztable"
CREATE TABLE
INSERT 0 3
 id | payload
----+---------
  1 | one
  2 | two
  3 | three
(3 rows)

UPDATE 2
 id | payload
----+---------
  1 | one
  2 | three
  3 | two
(3 rows)

NOTICE:  ALTER TABLE / ADD UNIQUE will create implicit index "omg_wtf" for table "ztable"
ALTER TABLE
UPDATE 2
 id | payload
----+---------
  1 | one
  2 | two
  3 | three
(3 rows)

Ulteriormente a Andy Irving risposta

questo ha funzionato per me (SQL Server 2005) in una situazione simile dove ho una chiave composta e ho bisogno di scambiare un campo che è parte dell'unico vincolo.

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

e ho bisogno di scambiare LNUM in modo che il risultato è

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

SQL necessario:

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

C'è un altro approccio che funziona con SQL Server:utilizzare una tabella temporanea join nell'istruzione UPDATE.

Il problema è causato dalla presenza di due righe con lo stesso valore allo stesso tempo, ma se si aggiorna entrambe le righe alla volta (per loro nuovi, unici valori), non vi è alcuna violazione del vincolo.

Pseudo-codice:

-- setup initial data values:
insert into data_table(id, name) values(1, 'A')
insert into data_table(id, name) values(2, 'B')

-- create temp table that matches live table
select top 0 * into #tmp_data_table from data_table

-- insert records to be swapped
insert into #tmp_data_table(id, name) values(1, 'B')
insert into #tmp_data_table(id, name) values(2, 'A')

-- update both rows at once! No index violations!
update data_table set name = #tmp_data_table.name
from data_table join #tmp_data_table on (data_table.id = #tmp_data_table.id)

Grazie alla Ricca H per questa tecnica.- Mark

Penso anche che il #2 è la soluzione migliore, anche se vorrei essere sicuri di avvolgere in una transazione nel caso in cui qualcosa va storto metà di aggiornamento.

Un'alternativa (dal momento che hai chiesto) per aggiornare l'Indice Univoco valori con valori diversi aggiornare tutti gli altri valori nelle righe a quella dell'altra fila.Fare questo significa che si potrebbe lasciare gli Unici valori di Indice da solo, e alla fine, si finisce con i dati che si desidera.Attenzione però, nel caso in cui qualche altra tabella fa riferimento a questa tabella, in una relazione di Chiave esterna, che tutti i rapporti in DB rimangono intatti.

Ho lo stesso problema.Ecco il mio approccio proposto in PostgreSQL.Nel mio caso, il mio unico indice è un valore di sequenza, la definizione di un esplicito dell'utente-ordine sul mio righe.L'utente provvederà a mischiare le righe intorno in una web-app, quindi inviare le modifiche.

Sto pensando di aggiungere un "prima" trigger.In tale trigger, ogni volta che il mio unico valore dell'indice viene aggiornato, proverò a vedere se qualche altra riga già detiene il mio nuovo valore.Se è così, io darò loro il mio vecchio valore, e in modo efficace rubare il valore fuori di loro.

Spero che PostgreSQL mi permetterà di fare questo shuffle prima di trigger.

I'll post indietro e ti faccio sapere il mio chilometraggio.

Supponendo che si conosce il PK di due righe che si desidera aggiornare...Questo funziona in SQL Server, posso parlare per gli altri prodotti.SQL è (dovrebbe essere) atomica a livello di istruzione:

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;

così si andrà da:

cola    colb
------------
1       b
2       a

a:

cola    colb
------------
1       a
2       b

Per Oracle c'è un'opzione, in DIFFERITA, ma devi aggiungere al tuo vincolo.

SET CONSTRAINT emp_no_fk_par DEFERRED; 

Di rinviare TUTTI i vincoli che sono rimandabile durante l'intera sessione, è possibile utilizzare l'istruzione ALTER SESSIONE di IMPOSTARE i vincoli=DIFFERITE istruzione.

Fonte

Oracle ha differito il controllo di integrità che risolve proprio questo, ma non è disponibile in SQL Server o MySQL.

In SQL Server, l'istruzione MERGE possibile aggiornare le righe che normalmente rompere una CHIAVE UNIVOCA/INDICE.(Appena testato questo perché ero curioso.)

Tuttavia, è necessario utilizzare una tabella temporanea/variabile per la fornitura di UNIRE w/ le righe necessarie.

Io di solito pensare a un valore assolutamente nessun indice nella tabella potrebbe avere.Di solito - per unica colonna di valori - è davvero facile.Per esempio, per i valori della colonna "posizione" (informazioni sull'ordine di diversi elementi) è 0.

Quindi è possibile copiare Un valore a una variabile, di aggiornamento con il valore di B e quindi impostare il valore di B variabile.Due query, so che non è la soluzione migliore però.

1) passare l'id per il nome

id    student 

1     Abbot   
2     Doris  
3     Emerson 
4     Green  
5     Jeames  

Per il campione di input, l'output è:

id studente

1     Doris   
2     Abbot   
3     Green   
4     Emerson 
5     Jeames  

"nel caso in cui il numero n di righe come gestire......"

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top