2010-07-14 5 views
2

lecteur de temps longue, première affiche de temps ;-)Au lieu de déclencher la mise à jour clé primaire

Je mettre en place un système basé sur un ancien système. Le nouveau système utilise SQL Server 2008 et mon problème vient lorsque vous essayez d'insérer de nouveaux éléments dans la table principale. Cela se produira de deux façons: Il peut être importé du système existant (1) ou peut être créé dans le nouveau système (2).

Dans le cas (1) l'article a déjà un ID (int) que je voudrais conserver. Dans le cas (2), l'ID ne sera pas rempli et je voudrais générer un ID qui est +1 de la valeur actuelle maximale dans la table. Cela devrait bien sûr également fonctionner pour les insertions de plusieurs rangées. Pour autant que je puisse voir, la solution sera de créer un INSTEAD OF TRIGGER, mais je n'arrive pas à comprendre comment cela se fait. Quelqu'un peut-il me donner un indice ou me diriger dans la direction de la façon dont cela peut être fait?

Chris

Répondre

1

Suite à votre demande d'utilisation d'un INSTEAD OF déclenchez ce code SQL peut vous aider à démarrer.

CREATE TABLE dbo.SampleTable 
(
    ID INT, 
    SomeOtherValue VARCHAR(100) NULL 
) 
GO 

CREATE TRIGGER dbo.TR_SampleTable_Insert 
    ON dbo.SampleTable 
    INSTEAD OF INSERT 
AS 
BEGIN 

    SET NOCOUNT ON; 

    -- Inserting rows with IDs 
    INSERT INTO dbo.SampleTable (
     ID, 
     SomeOtherValue) 
    SELECT 
     ID, 
     SomeOtherValue 
    FROM 
     Inserted  
    WHERE 
     ID IS NOT NULL 

    -- Now inserting rows without IDs 
    INSERT INTO dbo.SampleTable (
     ID, 
     SomeOtherValue) 
    SELECT 
     (SELECT ISNULL(MAX(ID), 0) FROM dbo.SampleTable) 
      + ROW_NUMBER() OVER(ORDER BY ID DESC), 
     SomeOtherValue 
    FROM 
     Inserted 
    WHERE 
     ID IS NULL 

END 
GO 

INSERT INTO dbo.SampleTable 
SELECT 1, 'First record with id' 
UNION 
SELECT NULL, 'First record without id' 
UNION 
SELECT 2, 'Second record with id' 
UNION 
SELECT NULL, 'Second record without id' 
GO 

SELECT * FROM dbo.SampleTable 
GO 
+0

Je suis entièrement d'accord avec les commentaires précédents que le mélange des anciens ID avec les nouveaux n'est pas recommandé. – JCallico

+0

Merci - juste le genre d'exemple que je cherchais :-) En ce qui concerne le mélange des identifiants, je vois l'inconvénient - mais le projet donne aussi quelques inconvénients à cette approche non pertinente à ce problème technique. –

+0

Je suis content d'avoir pu aider.C'est pourquoi j'ai mis en œuvre ce que vous avez demandé à l'origine au lieu de suggérer immédiatement une approche alternative juste pour le plaisir d'obtenir des points de vous. Cela ressemble à une tendance sur StackOverflow ces jours-ci. – JCallico

1

Que diriez-vous à l'aide d'une procédure stockée pour faire vos inserts, avec la clé primaire comme un paramètre optionnel. Dans la procédure stockée, vous pouvez définir la clé primaire lorsqu'elle n'est pas transmise. Je vous préviens que si des enregistrements anciens et nouveaux sont insérés, le scénario échouera probablement, car les nouveaux enregistrements recevront d'anciens ID avant que les anciens enregistrements ne soient insérés. Je recommande d'obtenir l'ID max de l'ancienne table maintenant, et dans la procédure stockée définir la nouvelle clé primaire à la plus grande valeur de (ancien max + 1, table actuelle max)

+0

Je vois cette option comme une possibilité, mais je trouve la solution de déclenchement plus propre, si cela est possible. Sinon, je vais sûrement aller pour la solution de procédure stockée. Concernant le crash de l'ID - Je suis conscient du problème, et je vais générer de nouveaux ID assez grand pour que le crash ne se produise jamais (je viens de quitter cette partie pour plus de simplicité). Ou, au moins pas pour 75 autres années - ce qui devrait suffire pour un système destiné à la ferraille l'année prochaine ;-) –

+0

Je pense que j'ai peut-être mal compris votre commentaire sur les anciens et les nouveaux ID. Et je pense que je n'ai pas assez bien décrit la situation. L'ancien système continuera à générer de nouveaux éléments, de sorte que les ID de l'ancien système continueront à augmenter en valeur même après la mise en production du nouveau système. Ce n'est que lorsque toutes les fonctionnalités auront été portées que l'ancien système sera mis au rebut. –

+0

@Chris - Droite J'étais sur le point de vous demander pourquoi vous ne pouviez pas importer tous les anciens enregistrements et en avoir fini avec cela, mais cela l'explique. –

0

D'autres vous ont montré comment écrire ce déclencheur.

Une autre approche, souvent recommandée, consiste à stocker les deux ID dans une nouvelle base de données. Chaque enregistrement obtient un nouvel ID dans le nouveau système (par colonne IDENTITY ou par d'autres moyens). En outre, si l'enregistrement est importé à partir d'un autre système, il est associé à OriginSystem et OriginID. De cette façon, vous pouvez conserver les anciens ID pour référence. Cette approche présente l'avantage supplémentaire de pouvoir prendre en charge un nouveau système pour importer des données, par ex. lors de la fusion ou de l'échange de données avec un autre système.

+0

C'est ce que je voudrais si le même problème se présentait. – JCallico

+0

Merci pour votre commentaire. Cette solution a été considérée. En raison des détails du projet qui ne sont pas décrits ici, cela compliquerait plus le modèle de données qu'il ne le semble (l'ancien système a d'autres systèmes de support qui doivent être également manipulés). La solution finale pour ce problème n'a pas encore été décidée - mais il est bon de savoir que la solution de déclenchement semble être une possibilité. –

Questions connexes