Поменяйте уникальные индексированные значения столбцов в базе данных

голоса
47

У меня есть таблица базы данных и одно из полей (не первичный ключ) имеет уникальный индекс на нем. Теперь я хочу поменять значения в этой колонке для двух строк. Как это можно сделать? Два писак я знаю, являются:

  1. Удалить обе строки и повторно вставить их
  2. Обновление строк с каким-либо другим значением и обмена, а затем обновить до фактического значения.

Но я не хочу, чтобы пойти на это, поскольку они, кажется, не является подходящим решением проблемы. Может кто-нибудь помочь мне?

Задан 03/08/2008 в 10:55
источник пользователем
На других языках...                            


12 ответов

голоса
8

Я думаю, вы должны пойти на решение 2. Там нет функции «своп» в любом варианте SQL я знаю.

Если вам нужно сделать, это регулярно, я предлагаю решение 1, в зависимости от того, как другие части программного обеспечения используют эти данные. Вы можете иметь запирающие вопросы, если вы не будете осторожны.

Но в общем, нет другого решения, чем те, которые вы указали.

Ответил 03/08/2008 в 13:26
источник пользователем

голоса
2

Я также думаю, что # 2 является лучшим выбором, хотя я был бы уверен, чтобы обернуть его в сделке в случае, если что-то пойдет не так в середине обновления.

Альтернативным (так как вы просили) для обновления значений уникального индекса с различными значениями будет обновлять все остальные значения в строках к тому из другого ряда. Делая это означает, что вы можете оставить значения уникальный индекс в одиночку, и в конце концов, вы в конечном итоге с данными, которые вы хотите. Будьте осторожны, в случае, если некоторые другие ссылки Эта таблица в ключе внешней связи, что все отношения в БД остаются нетронутыми.

Ответил 03/08/2008 в 14:22
источник пользователем

голоса
2

Предполагая, что вы знаете PK из двух строк, которые вы хотите обновить ... Это работает в SQL Server, не может говорить за другие продукты. SQL есть (должен быть) атомными на уровне оператора:

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;

так что вы будете идти от:

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

чтобы:

cola    colb
------------
1       a
2       b
Ответил 16/09/2008 в 15:57
источник пользователем

голоса
5

В дополнение к ответу Энди Ирвина

это работало для меня (на SQL Server 2005), в аналогичной ситуации, когда у меня есть составной ключ и мне нужно поменять поле, которое является частью уникального ограничения.

Ключ: Pid, ​​LNUM REC1: 10, 0 rEC2: 10, 1 rec3: 10, 2

и мне нужно поменять LNUM так что результат

Ключ: Pid, ​​LNUM REC1: 10, 1 rEC2: 10, 2 rec3: 10, 0

SQL, необходимо:

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))
Ответил 10/12/2008 в 13:19
источник пользователем

голоса
2

У меня такая же проблема. Вот мой предложенный подход в PostgreSQL. В моем случае, мой уникальный индекс представляет собой значение последовательности, определяя явный пользовательский порядок на своих рядах. Пользователь будет тасовать строки вокруг в веб-приложение, а затем представить изменения.

Я планирую добавить «до» триггера. В этом триггере, когда мое уникальное значение индекса обновляется, я буду смотреть, чтобы увидеть, если любая другая строка уже имеет свое новое значение. Если да, то я дам им свое старое значение, и эффективно украсть ценность от них.

Я надеюсь, что PostgreSQL позволит мне сделать это в случайном порядке до запуска.

Я отправлю обратно, и пусть вы знаете, мой пробег.

Ответил 24/06/2009 в 04:58
источник пользователем

голоса
1

Oracle отложила проверки целостности, который решает именно это, но он не доступен в любой SQL Server или MySQL.

Ответил 19/03/2010 в 20:29
источник пользователем

голоса
5

Существует и другой подход, который работает с SQL Server: использовать временную таблицу, присоединиться к нему в вашем UPDATE заявление.

Проблема вызвана тем , что две строки с одинаковым значением в то же время , но если обновить обе строки сразу (их новых уникальных значения), нет нарушения ограничения.

Псевдо-код:

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

Благодаря Rich H для этой техники. - Отметка

Ответил 04/04/2012 в 20:40
источник пользователем

голоса
1

В SQL Server, оператор MERGE может обновлять строки, которые обычно ломаются уникальный ключ / INDEX. (Только проверил это, потому что мне было интересно.)

Тем не менее, вы должны использовать временную таблицу / переменную для питания MERGE ж / необходимых строк.

Ответил 20/04/2012 в 20:12
источник пользователем

голоса
21

Волшебное слово откладываемые здесь:

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;

РЕЗУЛЬТАТ:

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)
Ответил 15/09/2012 в 13:38
источник пользователем

голоса
1

Для Oracle есть вариант, DEFERRED, но вы должны добавить его в ограничении.

SET CONSTRAINT emp_no_fk_par DEFERRED; 

Перенести все ограничения, которые откладываемые в течение всего сеанса, вы можете использовать ALTER SESSION SET ТРУДНОСТИ = DEFERRED заявление.

Источник

Ответил 27/04/2016 в 14:15
источник пользователем

голоса
0

Обычно я думаю о том, что значение абсолютно никакого индекса в моей таблице не может иметь. Обычно - для уникальных значений столбца - это очень легко. Например, для значений столбца «позиции» (информация о порядке нескольких элементов) это 0.

Затем вы можете скопировать значение A переменной, обновить его со значением B и затем установить значение B с переменной. Два запросов, я не знаю лучшего решения, хотя.

Ответил 18/03/2017 в 18:00
источник пользователем

голоса
1

1) переключить идентификаторы для имени

id    student 

1     Abbot   
2     Doris  
3     Emerson 
4     Green  
5     Jeames  

Для ввода образца, выход:

студенческий

1     Doris   
2     Abbot   
3     Green   
4     Emerson 
5     Jeames  

«В случае п числа строк, как будет управлять ......»

Ответил 06/11/2018 в 08:56
источник пользователем

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