J'ai besoin d'écrire une procédure stockée T-SQL qui met à jour une ligne dans une table. Si la ligne n'existe pas, insérez-la. Toutes ces étapes enveloppées par une transaction.
Il s'agit d'un système de réservation, il doit donc être atomique et fiable . Il doit retourner vrai si la transaction a été commise et le vol réservé.
Je suis nouveau sur T-SQL et je ne sais pas comment l'utiliser @@rowcount
. C'est ce que j'ai écrit jusqu'à présent. Suis-je sur la bonne route? Je suis sûr que c'est un problème facile pour vous.
-- BEGIN TRANSACTION (HOW TO DO?)
UPDATE Bookings
SET TicketsBooked = TicketsBooked + @TicketsToBook
WHERE FlightId = @Id AND TicketsMax < (TicketsBooked + @TicketsToBook)
-- Here I need to insert only if the row doesn't exists.
-- If the row exists but the condition TicketsMax is violated, I must not insert
-- the row and return FALSE
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO Bookings ... (omitted)
END
-- END TRANSACTION (HOW TO DO?)
-- Return TRUE (How to do?)
sql
sql-server
sql-server-2008
tsql
Whymarrh
la source
la source
Réponses:
Jetez un œil à la commande MERGE . Vous pouvez le faire
UPDATE
,INSERT
&DELETE
en une seule déclaration.Voici une implémentation de travail sur l'utilisation
MERGE
- Il vérifie si le vol est plein avant de faire une mise à jour, sinon fait un insert.
Puis ...
la source
J'assume une seule ligne pour chaque vol? Si c'est le cas:
Je suppose que ce que j'ai dit, car votre façon de faire peut surréserver un vol, car elle insérera une nouvelle ligne lorsqu'il y aura 10 billets maximum et que vous en réserverez 20.
la source
BEGIN TRAN ... COMMIT
niveau d'isolement sous par défaut ne résoudra pas le problème. L'OP a précisé que atomique et fiable étaient des exigences. Votre réponse ne parvient pas à résoudre ce problème sous quelque forme que ce soit.IF EXISTS (SELECT * FROM Bookings (UPDLOCK, HOLDLOCK) WHERE FLightID = @Id)
?Passez les astuces updlock, rowlock, holdlock lorsque vous testez l'existence de la ligne.
Le conseil de mise à jour force la requête à prendre un verrou de mise à jour sur la ligne si elle existe déjà, empêchant d'autres transactions de la modifier jusqu'à ce que vous validiez ou annuliez.
L'astuce de verrouillage oblige la requête à prendre un verrou de plage, empêchant d'autres transactions d'ajouter une ligne correspondant à vos critères de filtre jusqu'à ce que vous validiez ou annuliez.
L'astuce rowlock force la granularité du verrouillage au niveau de la ligne au lieu du niveau de page par défaut, de sorte que votre transaction ne bloquera pas les autres transactions essayant de mettre à jour des lignes non liées dans la même page (mais soyez conscient du compromis entre la réduction des conflits et l'augmentation de la frais généraux de verrouillage - vous devez éviter de prendre un grand nombre de verrous au niveau des lignes en une seule transaction).
Voir http://msdn.microsoft.com/en-us/library/ms187373.aspx pour plus d'informations.
Notez que les verrous sont pris lorsque les instructions qui les prennent sont exécutées - l'invocation de begin tran ne vous donne pas l'immunité contre une autre transaction qui pince les verrous sur quelque chose avant d'y arriver. Vous devez essayer de factoriser votre SQL pour maintenir les verrous le plus rapidement possible en validant la transaction dès que possible (acquisition tardive, libération anticipée).
Notez que les verrous au niveau de la ligne peuvent être moins efficaces si votre PK est un gros point, car le hachage interne sur SQL Server est dégénéré pour les valeurs 64 bits (différentes valeurs de clé peuvent hacher vers le même ID de verrouillage).
la source
exists
vérification supplémentaire préventive sans conseils de verrouillage.j'écris ma solution. ma méthode ne tient pas "si" ou "fusionner". ma méthode est simple.
Par exemple:
Explication:
(1) SELECT col1, col2 FROM TableName WHERE col1 = @ par1 AND col2 = @ par2 Il sélectionne parmi les valeurs recherchées TableName
(2) SELECT @ par1, @ par2 WHERE NOT EXISTS Il faut s'il n'existe pas de (1) sous-requête
(3) Insère dans les valeurs d'étape TableName (2)
la source
J'ai finalement pu insérer une ligne, à condition qu'elle n'existait pas déjà, en utilisant le modèle suivant:
que j'ai trouvé sur:
http://www.postgresql.org/message-id/[email protected]
la source
C'est quelque chose que j'ai récemment dû faire:
la source
Vous pouvez utiliser la fonctionnalité de fusion pour y parvenir. Sinon, vous pouvez faire:
la source
La solution complète est ci-dessous (y compris la structure du curseur). Un grand merci à Cassius Porcus pour le
begin trans ... commit
code affiché ci-dessus.la source
la source
la source
La meilleure approche de ce problème consiste à rendre la colonne de base de données UNIQUE
ALTER TABLE table_name ADD UNIQUE KEY
THEN INSERT IGNORE INTO table_name
, la valeur ne sera pas insérée si elle se traduit par une clé en double / existe déjà dans la table.la source