DESABILITAR ADBLOCK

ADBlock está bloqueando algum conteúdo do site

ADBlock errore

Trocar valores coluna indexada únicas no banco de dados

StackOverflow https://stackoverflow.com/questions/644

Pergunta

Eu tenho uma tabela de banco de dados e um dos campos (não a chave primária) está tendo um índice exclusivo sobre ele. Agora eu quero valores de swap nesta coluna para duas linhas. Como isso poderia ser feito? Dois hacks que eu conheço são:

  1. Excluir linhas e re-inseri-los.
  2. linhas
  3. UPDATE com algum outro valor e trocar e atualizar a valor real.

Mas eu não quero ir para estes como eles não parecem ser a solução adequada para o problema. Alguém poderia me ajudar?

Solução

Eu acho que você deve ir para a solução 2. Não existe a função 'swap' em qualquer variante SQL eu saiba.

Se você precisa fazer isso regularmente, sugiro solução 1, dependendo de como outras partes do software estão usando esses dados. Você pode ter problemas de bloqueio se você não tiver cuidado.

Mas em suma:. Não há nenhuma outra solução do que os que você forneceu

OUTRAS DICAS

A palavra mágica é DEFERRABLE aqui:

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)

Na sequência da resposta de Andy Irving

Isso funcionou para mim (em SQL Server 2005) em uma situação semelhante onde eu tenho uma chave composta e eu preciso trocar um campo que faz parte da restrição exclusiva.

chave: PID, lnum rec1: 10, 0 rec2: 10, 1 rec3: 10, 2

e eu preciso lnum swap de modo que o resultado é

chave: PID, lnum rec1: 10, 1 rec2: 10, 2 rec3: 10, 0

o SQL necessário:

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

Há uma outra abordagem que funciona com SQL Server:. Utilizar uma tabela temporária se juntar a ele em sua declaração UPDATE

O problema é causado por ter duas linhas com o mesmo valor ao mesmo tempo , mas se você atualizar ambas as linhas de uma vez (para os valores novos, originais), não há violação de restrição.

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)

Graças ao rico H para esta técnica. - Mark

Eu também acho que # 2 é a melhor aposta, embora eu estaria certo para envolvê-lo em uma transação no caso de algo der errado no meio da atualização.

Uma alternativa (desde que você pediu) para atualizar os valores índice exclusivo com valores diferentes seria para atualizar todos os outros valores nas linhas para o da outra linha. Fazer isso significa que você pode deixar os valores índice exclusivo sozinho, e no final, você acaba com os dados que você quer. Seja porém cuidadoso, no caso de algumas outras referências da tabela esta tabela em um relacionamento de chave estrangeira, que todos os relacionamentos no DB permanecem intactos.

Eu tenho o mesmo problema. Aqui está a minha abordagem proposta no PostgreSQL. No meu caso, meu índice exclusivo é um valor seqüência, a definição de um user-ordem explícita nas minhas linhas. O usuário irá embaralhar linhas em torno de um web-app, em seguida, apresentar as alterações.

Estou a planear adicionar um "antes" gatilho. Nesse gatilho, sempre que o meu valor índice exclusivo é atualizado, vou olhar para ver se qualquer outra linha já detém o meu novo valor. Se assim for, vou dar-lhes o meu valor antigo, e eficazmente roubar o valor fora deles.

Eu estou esperando que PostgreSQL vai me permitir fazer isso shuffle na antes gatilho.

Vou postar de volta e que você saiba a minha quilometragem.

Assumindo que você sabe que o PK das duas linhas que deseja atualizar ... Isso funciona no SQL Server, não posso falar por outros produtos. SQL é (supostamente) atômica no nível de instrução:

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;

então você vai de:

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

para:

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

Para o Oracle não é uma opção, adiado, mas você tem que adicioná-lo à sua restrição.

SET CONSTRAINT emp_no_fk_par DEFERRED; 

restrições de adiar todas que são deferrable durante toda a sessão, você pode usar o ALTER SESSION SET restrições = declaração diferido.

Fonte

A Oracle adiada verificação de integridade que resolve exatamente isso, mas ele não está disponível em qualquer SQL Server ou MySQL.

No SQL Server, a instrução MERGE pode atualizar linhas que normalmente quebrar uma UNIQUE KEY / INDEX. (Apenas testado isso porque eu estava curioso.)

No entanto, você teria que usar uma tabela temp / variável para MERGE oferta c / as linhas necessárias.

Eu costumo pensar em um valor que absolutamente nenhum índice na minha mesa poderia ter. Geralmente - para os valores de coluna exclusivos - é realmente fácil. Por exemplo, para os valores da coluna 'posição' (as informações sobre a ordem de vários elementos) é 0.

Em seguida, você pode copiar o valor Uma a uma variável, atualizá-lo com valor B e, em seguida, definir o valor B de sua variável. Duas consultas, eu sei há melhor solução embora.

1) mudar os ids para o nome

id    student 

1     Abbot   
2     Doris  
3     Emerson 
4     Green  
5     Jeames  

Para a entrada de exemplo, a saída é:

estudante id

1     Doris   
2     Abbot   
3     Green   
4     Emerson 
5     Jeames  

"no caso de n número de linhas como irão gerenciar ......"

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