Necesito escribir un procedimiento almacenado T-SQL que actualice una fila en una tabla. Si la fila no existe, insértela. Todos estos pasos envueltos por una transacción.
Esto es para un sistema de reserva, por lo que debe ser atómico y confiable . Debe devolver verdadero si la transacción fue confirmada y el vuelo reservado.
Soy nuevo en T-SQL y no estoy seguro de cómo usarlo @@rowcount
. Esto es lo que he escrito hasta ahora. ¿Estoy en el camino correcto? Estoy seguro de que es un problema fácil para ti.
-- 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
fuente
fuente
Respuestas:
Echa un vistazo al comando MERGE . Puedes hacerlo
UPDATE
,INSERT
yDELETE
en una sola declaración.Aquí hay una implementación funcional sobre el uso
MERGE
: comprueba si el vuelo está lleno antes de realizar una actualización; de lo contrario, realiza una inserción.
Y entonces ...
fuente
¿Asumo una sola fila para cada vuelo? Si es así:
Supongo lo que dije, ya que su forma de hacer las cosas puede sobrecargar un vuelo, ya que insertará una nueva fila cuando haya un máximo de 10 boletos y usted reserve 20.
fuente
BEGIN TRAN ... COMMIT
nivel de aislamiento por defecto no resolverá el problema. El OP especificó que los requisitos atómicos y confiables eran requisitos. Su respuesta no aborda esto de ninguna forma o forma.IF EXISTS (SELECT * FROM Bookings (UPDLOCK, HOLDLOCK) WHERE FLightID = @Id)
:?Pase pistas de updlock, rowlock, holdlock cuando pruebe la existencia de la fila.
La sugerencia de updlock obliga a la consulta a tomar un bloqueo de actualización en la fila si ya existe, evitando que otras transacciones la modifiquen hasta que se confirme o retroceda.
La sugerencia de bloqueo obliga a la consulta a tomar un bloqueo de rango, evitando que otras transacciones agreguen una fila que coincida con sus criterios de filtro hasta que se confirme o retroceda.
La sugerencia de bloqueo de fila fuerza la granularidad de bloqueo al nivel de fila en lugar del nivel de página predeterminado, por lo que su transacción no bloqueará otras transacciones que intenten actualizar filas no relacionadas en la misma página (pero tenga en cuenta la compensación entre la contención reducida y el aumento en gastos generales de bloqueo: debe evitar tomar grandes cantidades de bloqueos a nivel de fila en una sola transacción).
Consulte http://msdn.microsoft.com/en-us/library/ms187373.aspx para obtener más información.
Tenga en cuenta que los bloqueos se toman a medida que se ejecutan las declaraciones que los toman: invocar begin tran no le da inmunidad contra otra transacción que aprieta los bloqueos en algo antes de llegar a él. Debe intentar factorizar su SQL para mantener los bloqueos durante el menor tiempo posible al confirmar la transacción lo antes posible (adquirir tarde, liberar temprano).
Tenga en cuenta que los bloqueos de nivel de fila pueden ser menos efectivos si su PK es un bigint, ya que el hashing interno en SQL Server se degenera para valores de 64 bits (diferentes valores de clave pueden dividirse en el mismo ID de bloqueo).
fuente
exists
verificación adicional preventiva sin sugerencias de bloqueo.Estoy escribiendo mi solución. mi método no soporta 'if' o 'merge'. Mi método es fácil.
Por ejemplo:
Explicación:
(1) SELECCIONE col1, col2 DESDE TableName DONDE col1 = @ par1 Y col2 = @ par2 Selecciona de los valores buscados de TableName
(2) SELECCIONE @ par1, @ par2 DONDE NO EXISTE Se necesita si no existe desde (1) subconsulta
(3) Se inserta en TableName (2) valores de paso
fuente
Finalmente pude insertar una fila, con la condición de que aún no existiera, usando el siguiente modelo:
que encontré en:
http://www.postgresql.org/message-id/[email protected]
fuente
Esto es algo que recientemente tuve que hacer:
fuente
Puede usar la Funcionalidad de fusión para lograr. De lo contrario, puede hacer:
fuente
La solución completa está debajo (incluida la estructura del cursor). Muchas gracias a Cassius Porcus por el
begin trans ... commit
código publicado anteriormente.fuente
fuente
fuente
El mejor enfoque para este problema es hacer que la columna de la base de datos sea ÚNICA
ALTER TABLE table_name ADD UNIQUE KEY
THEN INSERT IGNORE INTO table_name
, el valor no se insertará si da como resultado una clave duplicada / ya existe en la tabla.fuente