Eu preciso escrever um procedimento armazenado T-SQL que atualize uma linha em uma tabela. Se a linha não existir, insira-a. Todas essas etapas estão envolvidas por uma transação.
Isso é para um sistema de reservas, portanto deve ser atômico e confiável . Ele deve retornar verdadeiro se a transação foi confirmada e o voo reservado.
Eu sou novo no T-SQL e não tenho certeza de como usá-lo @@rowcount
. Isto é o que eu escrevi até agora. Estou no caminho certo? Tenho certeza que é um problema fácil para você.
-- 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
fonte
fonte
Respostas:
Dê uma olhada no comando MERGE . Você pode fazer
UPDATE
,INSERT
&DELETE
em uma declaração.Aqui está uma implementação funcional sobre o uso
MERGE
- Ele verifica se o vôo está cheio antes de fazer uma atualização, caso contrário, faz uma inserção.
E depois ...
fonte
Presumo uma única linha para cada voo? Se então:
Suponho o que eu disse, pois sua maneira de fazer as coisas pode reservar em excesso um voo, pois inserirá uma nova linha quando houver 10 bilhetes no máximo e você fizer 20 reservas.
fonte
BEGIN TRAN ... COMMIT
nível de isolamento abaixo do padrão não resolverá o problema. O OP especificou que atômicos e confiáveis eram requisitos. Sua resposta falha ao resolver isso de qualquer forma.IF EXISTS (SELECT * FROM Bookings (UPDLOCK, HOLDLOCK) WHERE FLightID = @Id)
:?Passe dicas de updlock, rowlock, holdlock ao testar a existência da linha.
A dica updlock força a consulta a receber um bloqueio de atualização na linha, se ela já existir, impedindo que outras transações a modifiquem até você confirmar ou retroceder.
A dica holdlock força a consulta a bloquear um intervalo, impedindo que outras transações adicionem uma linha que corresponda aos seus critérios de filtro até você confirmar ou retroceder.
A dica de bloqueio de linha força a granularidade de bloqueio ao nível da linha, em vez do nível da página padrão, para que sua transação não bloqueie outras transações que tentam atualizar linhas não relacionadas na mesma página (mas esteja ciente da troca entre contenção reduzida e aumento de sobrecarga de bloqueio - evite usar um grande número de bloqueios no nível de linha em uma única transação).
Consulte http://msdn.microsoft.com/en-us/library/ms187373.aspx para obter mais informações.
Observe que os bloqueios são tomados como as instruções que os executam são executados - invocar begin tran não dá imunidade a outra transação que bloqueia bloqueios em algo antes de você chegar a ele. Você deve tentar fatorar seu SQL para reter bloqueios pelo menor tempo possível, confirmando a transação o mais rápido possível (adquira tarde, libere antecipadamente).
Observe que os bloqueios no nível da linha podem ser menos eficazes se a sua PK for grande, pois o hash interno no SQL Server é degenerado para valores de 64 bits (valores de chave diferentes podem ser hash para o mesmo ID de bloqueio).
fonte
exists
sem dicas de bloqueio.estou escrevendo minha solução. meu método não é 'se' ou 'mesclar'. meu método é fácil.
Por exemplo:
Explicação:
(1) SELECT col1, col2 FROM TableName WHERE col1 = @ par1 AND col2 = @ par2 Seleciona os valores pesquisados do TableName
(2) SELECT @ par1, @ par2 ONDE NÃO EXISTE Demora se não existir na (1) subconsulta
(3) Insere os valores das etapas TableName (2)
fonte
Finalmente, consegui inserir uma linha, com a condição de ela ainda não existir, usando o seguinte modelo:
que eu encontrei em:
http://www.postgresql.org/message-id/[email protected]
fonte
Isso é algo que recentemente tive que fazer:
fonte
Você pode usar a funcionalidade de mesclagem para alcançar. Caso contrário, você pode fazer:
fonte
A solução completa está abaixo (incluindo a estrutura do cursor). Muito obrigado a Cassius Porcus pelo
begin trans ... commit
código da postagem acima.fonte
fonte
fonte
A melhor abordagem para esse problema é primeiro tornar a coluna do banco de dados ÚNICA
ALTER TABLE table_name ADD UNIQUE KEY
THEN INSERT IGNORE INTO table_name
, o valor não será inserido se resultar em uma chave duplicada / já existir na tabela.fonte