2017-10-09 2 views
2

J'ai une table existante avec des enregistrements et je viens d'ajouter une nouvelle colonne ver que je voudrais être unique. Je suis aux prises avec la façon de faire cela pour une raison quelconque.mise à jour des enregistrements existants avec un entier unique

Je veux faire quelque chose comme:

update foo set ver = (select generate_series(1, 1000)); 

ou peut-être

update foo set ver = v from (select generate_series(1, 1000) as v); 

... mais bien sûr, aucun de ces travaux. Quelqu'un peut-il souligner l'évidence pour moi?

+1

Si vous voulez que, pour être unique pour les futures lignes aussi bien, puis utiliser une séquence –

+0

@a_horse_with_no_name - non, je ne ai pas besoin (ou si vous voulez) que. Je dois juste m'assurer que les enregistrements existants deviennent uniques. (Dans mon code actuel, j'écris une migration SQL qui pourrait être appliquée à une base de données de production: ajoutez la colonne, remplissez la colonne, ajoutez un index unique.) –

Répondre

4

Vous avez besoin d'une clé primaire (ou une colonne unique) de mettre à jour individuellement les lignes d'une table. En l'absence d'une telle colonne, vous pouvez utiliser la colonne cachée ctid qui est unique par définition, par exemple:

update foo f 
set ver = rn 
from (
    select ctid, row_number() over (order by ctid) as rn 
    from foo 
    ) s 
where f.ctid = s.ctid 
+0

Eh bien, cela fonctionne certainement, mais je pense que ça va me prendre un moment pour comprendre pourquoi ... en fait, ma table réelle a un identifiant unique et j'ai actuellement résolu le problème avec 'update foo set ver = id;' - mais je ne peux pas croire que c'est le seul ou le meilleur Solution! –

+0

Vous pouvez utiliser 'id' au lieu de' ctid'. La solution donne des numéros consécutifs à partir de 1. Bien sûr, une simple attribution de 'id' est la meilleure option si elle répond à toutes vos exigences. – klin

+0

Cochez. C'est la réponse la plus soignée et c'est très intelligent. (Est-ce que cela inquiète quelqu'un d'autre que nous devons recourir à ce niveau d'intelligence, cependant?) –

1

Utilisez un code PL/pgSQL:

DO 
$$DECLARE 
    c CURSOR FOR SELECT * FROM foo; 
    x foo; 
    i integer := 1; 
BEGIN 
    OPEN c; 
    LOOP 
     FETCH c INTO x; 
     EXIT WHEN NOT FOUND; 
     UPDATE foo SET ver = i WHERE CURRENT OF c; 
     i := i + 1; 
    END LOOP; 
END;$$; 

vous pouvez ajouter une contrainte unique:

ALTER TABLE foo ADD UNIQUE(ver); 
0

D'abord, créer une séquence.

create sequence foo_ver; 

puis d'ajouter la colonne avec une valeur par défaut du nombre suivant dans la séquence. Les données sont automatiquement remplies et les nouveaux enregistrements reçoivent automatiquement un nouveau numéro unique.

Facultatif: créez un index unique pour être sûr.

create unique index on foo(ver); 
+0

J'ai déjà dit que je ne voulais pas faire cela. À l'avenir, cette colonne ne sera pas une simple séquence. Il sera rempli par l'application. J'ai juste besoin d'un moyen de remplir les dossiers existants - comme je l'ai dit dans les commentaires à la question. –

+0

Question: Pourquoi n'avez-vous pas besoin de nouveaux enregistrements pour être également uniques? –

+0

Pour plus d'informations, veuillez relire mon commentaire original à votre réponse. ;) –