ОТКЛЮЧИТЬ АДБЛОК

ADBlock блокирует некоторый контент на сайте

ADBlock errore
Найдены результаты: 

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

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

вопрос

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

<Ол>
  • Удалите обе строки и вставьте их снова.
  • Обновить строки другим значением и поменяйте местами, а затем обновите до фактического значения.

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

  • Решение

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

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

    Но вкратце: нет другого решения, кроме предложенного вами.

    Если хотите, оставьте нам свое мнение

    Была ли статья полезна и правильно ли она переведена?

    ДРУГИЕ СОВЕТЫ

    Волшебное слово ОТЛИЧНО здесь:

    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;
    
    <Р> РЕЗУЛЬТАТ:

    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)
    

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

    это сработало для меня (на 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))
    

    Существует другой подход, который работает с 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 за эту технику. - Марк

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

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

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

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

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

    Я отправлю сообщение и сообщу мой пробег.

    Предполагая, что вы знаете 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 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;
    

    так что вы пойдете из:

    cola    colb
    ------------
    1       b
    2       a
    
    <Р> в

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

    Для Oracle есть опция DEFERRED, но вы должны добавить ее к своему ограничению.

    SET CONSTRAINT emp_no_fk_par DEFERRED; 
    

    Чтобы отложить ВСЕ ограничения, которые откладываются в течение всего сеанса, вы можете использовать инструкцию ALTER SESSION SET constraints = DEFERRED.

    Источник

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

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

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

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

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

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

    id    student 
    
    1     Abbot   
    2     Doris  
    3     Emerson 
    4     Green  
    5     Jeames  
    

    Для примера ввода вывод:

    идентификатор студента

    1     Doris   
    2     Abbot   
    3     Green   
    4     Emerson 
    5     Jeames  
    

    " в случае n количество строк, как будет работать ...... "

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