Vyměnit jedinečné indexované hodnoty sloupců v databázi

hlasů
47

Mám databázové tabulky a jedno z polí (ne primární klíč) má jedinečný index na něj. Teď chci vyměnit hodnoty v tomto sloupci pro dvě řady. Jak by to mohlo být provedeno? Dva hacky, které znám, jsou:

  1. Odstranit oba řádky a vložte je zpět
  2. Aktualizaci řádků s jinou hodnotou a odkládacího prostoru a potom aktualizujte na skutečné hodnoty.

Ale já nechci jít na to, jak se nezdá být vhodným řešením problému. Mohl by mi někdo pomoci?

Položena 03/08/2008 v 10:55
zdroj uživatelem
V jiných jazycích...                            


12 odpovědí

hlasů
21

Kouzelné slovo je DEFERRABLE zde:

DROP TABLE ztable CASCADE;
CREATE TABLE ztable
    ( id integer NOT NULL PRIMARY KEY
    , payload varchar
    );
INSERT IGNORE  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;

VÝSLEDEK:

DROP TABLE
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "ztable_pkey" for table "ztable"
CREATE TABLE
INSERT IGNORE  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)
Odpovězeno 15/09/2012 v 13:38
zdroj uživatelem

hlasů
8

Myslím, že byste měli jít na řešení 2. Neexistuje žádná funkce ‚swap‘ v každém SQL variantě vím.

Potřebujete-li to pravidelně, navrhuji řešení 1, v závislosti na tom, jak ostatní části softwaru je využívání těchto údajů. Můžete mít uzamčení problémy, pokud si nedáte pozor.

Ale v krátkosti: neexistuje jiné řešení než ty, které jste poskytli.

Odpovězeno 03/08/2008 v 13:26
zdroj uživatelem

hlasů
5

Tam je jiný přístup, který pracuje s SQL Server: používat temp tabulky připojí k němu v příkazu UPDATE.

Problém je způsoben tím, že má dva řádky se stejnou hodnotou ve stejnou dobu , ale pokud budete aktualizovat oba řádky najednou (do svých nových, jedinečných hodnot), nedochází k porušení omezení.

Pseudo kód:

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

Díky Rich H pro tuto techniku. - Mark

Odpovězeno 04/04/2012 v 20:40
zdroj uživatelem

hlasů
5

V návaznosti na Andy Irvinga odpověď

to fungovalo pro mě (SQL Server 2005) v podobné situaci, kdy mám složený klíč a musím vyměnit oblasti, která je součástí jedinečného omezení.

klíč: PID, LNUM rec1: 10, 0 REC2: 10, 1 REC3: 10, 2

a musím vyměnit LNUM takže výsledkem je

klíč: PID, LNUM rec1: 10, 1 REC2: 10, 2 REC3: 10, 0

SQL potřeba:

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))
Odpovězeno 10/12/2008 v 13:19
zdroj uživatelem

hlasů
2

Mám stejný problém. Tady je můj navrhovaný přístup v PostgreSQL. V mém případě, můj jedinečný index je hodnota sekvence, definující explicitní uživatelského objednávku na svých řadách. Uživatel bude zamíchat řádky kolem v internetové aplikace, poté předložit změny.

Mám v plánu přidat „před“ spoušť. V té spoušti, kdykoliv je aktualizován můj jedinečná hodnota indexu, budu zjistit, zda nějaký jiný řádek již drží svou novou hodnotu. Pokud ano, budu jim svou starou hodnotu a účinně krást hodnotu off nimi.

Doufám, že PostgreSQL dovolí, abych udělal toto Shuffle v před spoušť.

Budu psát zpátky a dáme vám vědět, můj najetých kilometrů.

Odpovězeno 24/06/2009 v 04:58
zdroj uživatelem

hlasů
2

Za předpokladu, že víte, že PK ze dvou řad, které chcete aktualizovat ... To funguje v SQL Server, nemůže mluvit za jiné produkty. SQL je (má být) atomové na úrovni příkazu:

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

CREATE UNIQUE INDEX UIX_testing_a ON testing(colb);

INSERT IGNORE  INTO testing VALUES (1, 'b');
INSERT IGNORE  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;

takže půjde od:

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

na:

cola    colb
------------
1       a
2       b
Odpovězeno 16/09/2008 v 15:57
zdroj uživatelem

hlasů
2

Také si myslím, že # 2 je nejlepší volbou, i když bych určitě ho zabalit do transakce v případě, že se něco pokazí uprostřed aktualizace.

Alternativní (protože jste požádal), aby aktualizace hodnot jedinečný index s různými hodnotami bude aktualizovat všechny ostatní hodnoty v řádcích na to druhé řady. Mohlo by to znamená, že byste mohl opustit hodnoty jedinečný index sám, a nakonec jste skončili s daty, která chcete. Buďte opatrní, i když v případě některých dalších stolní reference tuto tabulku v cizí klíč vztah, že všechny vztahy v NR zůstanou nedotčeny.

Odpovězeno 03/08/2008 v 14:22
zdroj uživatelem

hlasů
1

1) přepínat identifikátory pro jméno

id    student 

1     Abbot   
2     Doris  
3     Emerson 
4     Green  
5     Jeames  

Pro vstup vzorku, výstup je:

id studenta

1     Doris   
2     Abbot   
3     Green   
4     Emerson 
5     Jeames  

„V případě, že n počet řádků, jak se bude řídit ......“

Odpovězeno 06/11/2018 v 08:56
zdroj uživatelem

hlasů
1

Pro Oracle je tu možnost, odložený, ale musíte jej přidat do svého omezení.

SET CONSTRAINT emp_no_fk_par DEFERRED; 

Odložit všem překážkám, které jsou deferrable během celé relace, můžete použít ALTER SESSION SET omezení = odložená prohlášení.

Zdroj

Odpovězeno 27/04/2016 v 14:15
zdroj uživatelem

hlasů
1

V SQL Server, výraz SLOUČENÍ může aktualizovat řádky, které by za normálních okolností zlomit jedinečný klíč / INDEX. (Jen zkouší to, protože jsem byl zvědavý.)

Nicméně, budete muset používat dočasnou tabulku / proměnnou dodat KORESPONDENCE w / potřebných řadách.

Odpovězeno 20/04/2012 v 20:12
zdroj uživatelem

hlasů
1

Oracle odložila kontrolu integrity, které řeší právě toto, ale není k dispozici buď v SQL Server nebo MySQL.

Odpovězeno 19/03/2010 v 20:29
zdroj uživatelem

hlasů
0

I obvykle myslí na hodnotu, která absolutně žádný index v mém stole by mohla mít. Obvykle - jedinečných hodnot sloupců - je to opravdu snadné. Například, pro hodnoty sloupce ‚polohy‘ (informace o pořadí několika prvků) je 0.

Pak můžete kopírovat hodnotu A k proměnné, aktualizovat s hodnotou B a pak nastavte hodnotu B od proměnné. Dva dotazy, vím, že nic lepšího řešení ačkoli.

Odpovězeno 18/03/2017 v 18:00
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more