Question

J'ai deux tables, nous allons les appeler et Foo Bar, avec une relation un à plusieurs où est le parent Select Max() de ID. la clé primaire de Foo est un nombre entier généré automatiquement avec une séquence.

Depuis est entièrement dépendante FooID sur FooBarID comment pourrais-je configurer la clé primaire de compte tenu des contraintes max(FooBarID)+1 suivantes:

  • records pour Bar sont programatically généré si l'entrée d'utilisateur ne peut pas être invoqué pour un identifiant.
  • Plusieurs processus génèrent dossiers de barre pour tout ce qui concerne un Pour générer un <=> serait <=> présenter une condition de course.

Je suis venu avec deux solutions possibles que je ne suis pas satisfait:

  • Traiter les tables comme si elles sont plusieurs à plusieurs avec un troisième table qui mappe leurs dossiers ensemble et que l'application Code INSERTION poignée enregistre ainsi des que la correspondance entre les enregistrements est créé correctement. Je n'aime pas Quoi qu'il en fait la conception de base de données induire en erreur et les erreurs dans l'application code pourrait conduire à des données non valides.
  • Donnez-Bar deux colunms: et <=> <=> et générer une valeur pour <=> en sélectionnant la Pour certains <=> <=>, mais comme indiqué précédemment ce qui crée un condition de course.

J'apprécie des idées pour une mise en page de table alternative.

Était-ce utile?

La solution

Donner une barre de clé primaire automatique la même que Foo. Ajouter une colonne de clé étrangère fooid Bar.

À moins que je me manque quelque chose, il ne semble pas être une raison pour laquelle cela ne fonctionnerait pas.

Autres conseils

À moins que je me manque quelque chose dans votre description, cela ressemble à un cas ordinaire. La solution habituelle est quelque chose comme ceci:

INSERT INTO Foo (foo_id, othercolumn)
  VALUES ( FooSeq.NextVal(), 'yadda yadda');

INSERT INTO Bar (bar_id, foo_id, extracolumn)
  VALUES ( BarSeq.NextVal(), FooSeq.CurrVal(), 'blah blah');
INSERT INTO Bar (bar_id, foo_id, extracolumn)
  VALUES ( BarSeq.NextVal(), FooSeq.CurrVal(), 'bling bling');
INSERT INTO Bar (bar_id, foo_id, extracolumn)
  VALUES ( BarSeq.NextVal(), FooSeq.CurrVal(), 'baz baz');

La fonction d'une CURRVAL() séquence renvoie uniquement la valeur la plus récente générée par cette séquence au cours de la session en cours . Autre utilisation simultanée de cette séquence n'affecte pas ce que le rendement de votre <=> session.

de votre description Je suppose que votre base de données ne supporte pas les champs d'identification automatique de l'incrément (MS SQL ne, Oracle a « séquences » qui sont tout aussi bien, sinon mieux, je ne me souviens pas MySql a).

Si elle le fait, tout ce que vous avez besoin est un fooid incrémentation automatique et un Barid incrémentation automatique et bar dispose également d'un fooid comme une clé étrangère

Si elle ne pas, vous pouvez créer une seule table rangée pour la répartition comme suit:

create table SystemCounter 
( 
    SystemCounterId int identity not null, 
    BarIdAllocator int 
)
--initialize SystemCounter to have one record with SystemCounterId = 1
--and BarIdAllocator = 0
insert into SystemCounter values (1,0)
--id allocator procedure
create procedure GetNextBarId ( @BarId int output ) AS
    SET NOCOUNT ON
    begin tran
        update SystemCounter set 
            @BarId = BarIdAllocator = BarIdAllocator + 1
        where SystemCounterId = 1
    commit
GO

Notez que si votre base de données ne prend pas en charge la syntaxe

@BarId = BarIdAllocator = BarIdAllocator + 1

alors vous aurez besoin de le faire de cette façon à la place

begin tran
    update SystemCounter set 
        BarIdAllocator = BarIdAllocator + 1
    where SystemCounterId = 1
    select 
        @BarId = BarIdAllocator
    from SystemCounter
    where SystemCounterId = 1
commit

EDIT: J'ai raté la balise Oracle à l'origine, donc la solution de projet de loi est tout ce qui est nécessaire. Je laisse cette réponse comme un exemple de la façon de le faire au cas où quelqu'un utilise une base de données qui ne supporte pas les constructions d'identité ou séquence

Je ne peux pas tout à fait voir non plus, comme par Ant de P et d'autres réponses, pourquoi qui générer juste un ID unique pour bar et laisser tomber l'ID de Foo ne fonctionnera pas. Mais en supposant que vous êtes dans une situation où les ID auto-incrémenter ne sont pas disponibles alors il y a deux solutions qui ne concernent pas la sélection max (Barid) +1

  1. Pre-générer une table des identifiants uniques et utiliser une transaction pour tirer le prochain ID disponible à partir de la table et le supprimer (comme une opération atomique). Cela fonctionne bien, mais présente l'inconvénient que vous devez garder la table peuplée.

  2. Générer un UUID comme la clé primaire. Ce ne sont généralement pas une bonne option, car UUID sont inefficaces pour cet usage, mais il a l'avantage qu'aucune table d'infrastructure supplémentaires sont nécessaires. générateurs UUID sont largement disponibles et certaines bases de données les ont construites.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top