DISABLE ADBLOCK

ADBlock está bloqueando parte del contenido en el sitio

ADBlock errore
resultados encontrados: 

Pregunta

Tengo una tabla de base de datos y uno de los campos (no la clave principal) tiene un índice único. Ahora quiero intercambiar valores en esta columna por dos filas. ¿Como se puede hacer esto? Dos hacks que conozco son:

  1. Borre ambas filas y reinsértelas.
  2. Actualizar filas con algún otro valor e intercambiar y luego actualizar a valor real.

Pero no quiero ir por estos, ya que no parecen ser la solución adecuada para el problema. ¿Alguien podría ayudarme?

Solución

Creo que deberías buscar la solución 2. No hay ninguna función de 'intercambio' en ninguna variante de SQL que conozca.

Si necesita hacer esto con regularidad, sugiero la solución 1, dependiendo de cómo otras partes del software están usando estos datos. Puede tener problemas de bloqueo si no tiene cuidado.

Pero en resumen: no hay otra solución que las que proporcionó.

Si te gusta déjanos tu opinión

¿Fue útil el artículo y está traducido correctamente?

OTROS CONSEJOS

La palabra mágica es DEFERRABLE aquí:

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;

RESULTADO:

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)

Más allá de la respuesta de Andy Irving

esto funcionó para mí (en SQL Server 2005) en una situación similar donde tengo una clave compuesta y necesito intercambiar un campo que forma parte de la restricción única.

tecla

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

y necesito intercambiar LNUM para que el resultado sea

tecla

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

el SQL necesario:

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

Hay otro enfoque que funciona con SQL Server: use una tabla temporal unida a ella en su declaración UPDATE.

El problema se debe a que tiene dos filas con el mismo valor al mismo tiempo , pero si actualiza ambas filas a la vez (a sus nuevos valores únicos), no hay infracción de restricción.

Pseudo-código:

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

Gracias a Rich H por esta técnica. - Mark

También creo que el # 2 es la mejor opción, aunque me aseguraría de incluirlo en una transacción en caso de que algo salga mal durante la actualización.

Una alternativa (dado que usted solicitó) a la actualización de los valores del Índice Único con valores diferentes sería actualizar todos los demás valores de las filas al de la otra fila. Hacer esto significa que podría dejar los valores del Índice Único solos, y al final, terminará con los datos que desea. Sin embargo, tenga cuidado, en caso de que alguna otra tabla haga referencia a esta tabla en una relación de clave externa, todas las relaciones en el DB permanecerán intactas.

Tengo el mismo problema. Aquí está mi propuesta de enfoque en PostgreSQL. En mi caso, mi índice único es un valor de secuencia, que define un orden de usuario explícito en mis filas. El usuario mezclará las filas en una aplicación web y luego enviará los cambios.

Estoy planeando agregar un " antes de " desencadenar. En ese activador, cada vez que mi valor de índice único se actualice, veré si alguna otra fila ya tiene mi nuevo valor. Si es así, les daré mi valor anterior y les robaré el valor de manera efectiva.

Espero que PostgreSQL me permita hacer esta mezcla en el gatillo anterior.

Volveré a publicar y te haré saber mi kilometraje.

Suponiendo que conoce la PK de las dos filas que desea actualizar ... Esto funciona en SQL Server, no se puede hablar de otros productos. SQL es (se supone que es) atómico a nivel de declaración:

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;

por lo que pasará de:

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

a:

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

Para Oracle hay una opción, DEFERIDA, pero tienes que agregarla a tu restricción.

SET CONSTRAINT emp_no_fk_par DEFERRED; 

Para aplazar TODAS las restricciones que son aplazables durante toda la sesión, puede usar las restricciones ALTER SESSION SET = DEFERRED.

Fuente

Oracle ha diferido la verificación de integridad que soluciona exactamente esto, pero no está disponible ni en SQL Server ni en MySQL.

En SQL Server, la instrucción MERGE puede actualizar filas que normalmente romperían un KEY / INDEX ÚNICO. (Solo probé esto porque tenía curiosidad).

Sin embargo, tendrías que usar una tabla / variable temporal para suministrar MERGE con las filas necesarias.

Por lo general, pienso en un valor que absolutamente ningún índice en mi tabla podría tener. Por lo general, para valores de columna únicos, es muy fácil. Por ejemplo, para los valores de la columna 'posición' (información sobre el orden de varios elementos) es 0.

Luego puede copiar el valor A a una variable, actualizarlo con el valor B y luego establecer el valor B de su variable. Dos consultas, aunque no conozco una mejor solución.

1) cambia los identificadores por nombre

id    student 

1     Abbot   
2     Doris  
3     Emerson 
4     Green  
5     Jeames  

Para la entrada de muestra, la salida es:

id estudiante

1     Doris   
2     Abbot   
3     Green   
4     Emerson 
5     Jeames  

" en el caso n número de filas, ¿cómo se gestionará ...... "

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow