2010-03-01 11 views
1

J'ai une table que les gens ont été l'insertion dans l'obtention de la clé primaire en faisant unel'aide d'une séquence sur une table existante

SELECT max(id)+1 from table_a; 

Je veux ajouter des enregistrements à cette table en utilisant un SQL simple, INSERT INTO table_a SELECT ... FROM table_b, table_c ... script, et je me demande comment générer les clés primaires. Ma première pensée était de créer une séquence temporaire, mais Oracle n'a évidemment pas de select setval pour définir la première valeur. Alors, comment puis-je obtenir la valeur actuelle de max (id) +1 pour définir le paramètre "start with" sur ma séquence?

je trouve quelque chose en ligne que je pensais travailler:

COLUMN S new_value st select max(id)+1 S from table_a; 
CREATE SEQUENCE cra_seq start with &st; 

Mais il n'utilise pas réellement st dans le CREATE SEQUENCE mais me invite à entrer, ce qui est pas ce que j'ai besoin.

+2

Il vous invite à entrer un paramètre car sql * plus échappe à "&". Mettez "set define off" comme première ligne de votre script et réessayez. –

+1

Avez-vous déjà eu l'occasion d'insérer plus d'une personne dans cette table en même temps? Si c'est le cas, toutes les méthodes d'utilisation de max (id) échoueront car chaque session simultanée se retrouvera avec le même identifiant max. Que diriez-vous juste de créer une séquence et l'utiliser comme source de vos identifiants pour toutes les insertions de table? –

+0

@Nick, croyez-moi, je sais à quel point la méthode "select max (id)" est horrible. J'ai essayé de les convaincre de passer à une séquence, mais les pouvoirs en place disent "oh, nous allons changer pour la prochaine sortie, donc ce sera ok pour l'instant". –

Répondre

3

Est-ce quelque chose comme ce que vous voulez?

1 declare 
    2 id integer; 
    3 begin 
    4 select max(rownum)+1 into id from dual; 
    5 execute immediate 'create sequence myseq start with '||TO_CHAR(id); 
    6* end; 
    7/
+0

Cela fonctionne aussi loin que ça va, mais la ligne suivante maintenant SQL * Developer se plaint que la ligne commençant par "INSERT" est en erreur, même si c'est bien si j'exécute cette ligne par elle-même. –

+0

Rapport d'erreur: ORA-06550: ligne 8, colonne 1: PLS-00103: rencontré le symbole "INSERER" 06550. 00000 - "ligne% s, colonne% s: \ n% s" * Cause: Habituellement une erreur de compilation PL/SQL. * Action: –

+0

Je pense que vous devez créer la séquence avant de compiler la procédure, puis la déposer à l'intérieur et la recréer. – DCookie

0

Vous pouvez utiliser row_number analytical function pour générer des numéros de ligne (1 à N).

Avant de procéder à l'insertion, récupérez l'identifiant max qui se trouve dans la table, puis ajoutez le numéro de ligne à ce maximum et il remplira correctement votre table.

+0

Je ne sais pas comment "obtenir l'identifiant max" dans un script SQL. –

+0

@Paul Tomblin: Je vous suggère de regarder la fonction "max" dans SQL. – casperOne

+0

Je sais comment afficher un identifiant max, je ne sais pas comment l'utiliser comme vous le suggérez. Il semble que vous parlez de le sélectionner dans une variable, et je n'ai aucune idée de la façon dont vous le faites dans un script sql. –

1

Ne pourriez-vous utiliser la fonction row_number comme ceci:

Insert Destination(Id, ...) 
Select row_number() over(order by TableA.Col1...) + MaxDestination.MaxId + 1 Num 
, .... 
From TableA, TableB,... 
Cross Join (Select Max(Id) MaxId From Destination) MaxDestination 
+0

Quel est le but de 'order by col1, col2' là-bas? –

+0

Shoot, maintenant il dit que "la commande SQL n'est pas correctement terminée". J'ai 'insérer dans table_a (id, a, b, c) sélectionnez row_number() sur (ordre par b) + maxcra.maxid + 1, d, e FROM table_b cross join (sélectionnez max (id) comme maxid à partir de table_a) comme maxcra où table_b.b = 'FOO'; ' –

+0

Col1, Col2 représentent des espaces réservés pour column.s La clause order by indique simplement au système comment ordonner les résultats pour déterminer le numéro de rangée. Si vous aviez une colonne nommée Nom et que vous vouliez que le nom trié le plus bas ait le numéro de ligne le plus bas, vous utiliseriez l'option Trier par nom. Je pense que vous devez changer "order by b" pour "order by table_b.b" cependant, je vais regarder plus loin ici. – Thomas

0

Dans PostgreSQL:

CREATE SEQUENCE new_seq; 
ALTER TABLE existing_table ADD COLUMN new_serial_column bigint DEFAULT 0; 
UPDATE existing_table SET new_serial_column = nextval('new_seq'); 
ALTER TABLE existing_table ALTER COLUMN new_serial_column SET NOT NULL; 
ALTER TABLE existing_table ALTER COLUMN new_serial_column SET DEFAULT nextval('new_seq'); 

Bien que le code est idempotente pas, afin de vérifier que vous havn't déjà créé la nouvelle séquence, quelque chose comme:

CREATE FUNCTION fixup_existing_table() RETURNS void AS $$ 
DECLARE 
    new_id bigint; 
    seq_column_exists integer; 
BEGIN 
    SELECT Count(column_name) INTO seq_column_exists FROM information_schema.columns WHERE table_name='existing_table' and column_name='new_serial_column'; 
IF seq_column_exists != 0 THEN RETURN; END IF; 

    CREATE SEQUENCE new_seq; 
    ALTER TABLE existing_table ADD COLUMN new_serial_column bigint DEFAULT 0; 
    UPDATE existing_table SET new_serial_column = nextval('new_seq'); 
    ALTER TABLE existing_table ALTER COLUMN new_serial_column SET NOT NULL; 
    ALTER TABLE existing_table ALTER COLUMN new_serial_column SET DEFAULT nextval('new_seq'); 
END; 
$$ LANGUAGE plpgsql; 

Ensuite, vous pouvez appeler en toute sécurité: SELECT fixup_existing_table() pour modifier le schéma autant de fois que vous le souhaitez, c'est-à-dire appeler depuis un script de mise à jour bête.

Questions connexes