valeur - sql server clé primaire auto increment




Échanger des valeurs de colonne indexées uniques dans la base de données (8)

1) changer les identifiants pour le nom

id    student 

1     Abbot   
2     Doris  
3     Emerson 
4     Green  
5     Jeames  

Pour l'exemple d'entrée, la sortie est:

étudiant id

1     Doris   
2     Abbot   
3     Green   
4     Emerson 
5     Jeames  

"dans le cas n nombre de lignes, comment allons-nous gérer ......"

J'ai une table de base de données et l'un des champs (pas la clé primaire) a un index unique. Maintenant, je veux échanger les valeurs sous cette colonne pour deux lignes. Comment cela pourrait-il être fait? Deux hacks que je connais sont:

  1. Supprimez les deux lignes et ré-insérez-les.
  2. Mettez à jour les lignes avec une autre valeur et échangez-les, puis mettez-les à jour.

Mais je ne veux pas y aller car ils ne semblent pas être la solution appropriée au problème. Quelqu'un pourrait m'aider?


Dans SQL Server, l'instruction MERGE peut mettre à jour des lignes qui rompraient normalement un UNIQUE KEY / INDEX. (Juste testé parce que j'étais curieux.)

Cependant, vous devrez utiliser une table / variable temporaire pour fournir MERGE avec les lignes nécessaires.


J'ai le même problème. Voici mon approche proposée dans PostgreSQL. Dans mon cas, mon index unique est une valeur de séquence, définissant un ordre utilisateur explicite sur mes lignes. L'utilisateur mélangera des lignes dans une application Web, puis soumettra les modifications.

Je prévois d'ajouter un déclencheur "avant". Dans ce déclencheur, chaque fois que ma valeur d'index unique est mise à jour, je vérifierai si une autre ligne contient déjà ma nouvelle valeur. Si tel est le cas, je leur donnerai mon ancienne valeur et la leur volera efficacement.

J'espère que PostgreSQL me permettra de faire ce mélange dans le déclencheur avant.

Je vous posterai et vous ferai savoir mon kilométrage.


Je pense aussi que le n ° 2 est le meilleur choix, bien que je sois sûr de l'envelopper dans une transaction au cas où quelque chose se passerait mal en cours de mise à jour.

Une alternative (puisque vous avez demandé) à la mise à jour des valeurs d'index unique avec des valeurs différentes serait de mettre à jour toutes les autres valeurs des lignes avec celles de l'autre ligne. Cela signifie que vous pouvez laisser les valeurs de l'index unique uniquement et que, finalement, vous obtenez les données souhaitées. Attention, si une autre table fait référence à cette table dans une relation de clé étrangère, toutes les relations de la base de données restent intactes.


Je pense que vous devriez aller chercher la solution 2. Il n'y a pas de fonction 'swap' dans les variantes SQL que je connaisse.

Si vous devez le faire régulièrement, je suggère la solution 1, en fonction de la manière dont les autres parties du logiciel utilisent ces données. Vous pouvez avoir des problèmes de verrouillage si vous ne faites pas attention.

Mais en bref: il n'y a pas d'autre solution que celles que vous avez fournies.


Le mot magique est DEFERRABLE ici:

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;

RÉSULTAT:

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)

Pour Oracle, il existe une option, DEFERRED, mais vous devez l'ajouter à votre contrainte.

SET CONSTRAINT emp_no_fk_par DEFERRED; 

Pour différer TOUTES les contraintes pouvant être différées pendant toute la session, vous pouvez utiliser l'instruction ALTER SESSION SET contraintes = DEFERRED.

Source


Suite à la réponse d'Andy Irving

cela a fonctionné pour moi (sur SQL Server 2005) dans une situation similaire où j'ai une clé composite et que je dois permuter un champ qui fait partie de la contrainte unique.

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

et je dois échanger LNUM pour que le résultat soit

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

le SQL nécessaire:

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






database