varias - validar si un registro existe en mysql
Compruebe si existe una fila, de lo contrario inserte (11)
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 usar @@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?)
¿Asumo una sola fila para cada vuelo? Si es así:
IF EXISTS (SELECT * FROM Bookings WHERE FLightID = @Id)
BEGIN
--UPDATE HERE
END
ELSE
BEGIN
-- INSERT HERE
END
Asumo 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 esté reservando 20.
Echa un vistazo al comando MERGE . Puede hacer UPDATE
, INSERT
Y DELETE
en una declaración.
Aquí está una implementación de trabajo en el uso de MERGE
- Comprueba si el vuelo está lleno antes de hacer una actualización, de lo contrario hace una inserción.
if exists(select 1 from INFORMATION_SCHEMA.TABLES T
where T.TABLE_NAME = ''Bookings'')
begin
drop table Bookings
end
GO
create table Bookings(
FlightID int identity(1, 1) primary key,
TicketsMax int not null,
TicketsBooked int not null
)
GO
insert Bookings(TicketsMax, TicketsBooked) select 1, 0
insert Bookings(TicketsMax, TicketsBooked) select 2, 2
insert Bookings(TicketsMax, TicketsBooked) select 3, 1
GO
select * from Bookings
Y entonces ...
declare @FlightID int = 1
declare @TicketsToBook int = 2
--; This should add a new record
merge Bookings as T
using (select @FlightID as FlightID, @TicketsToBook as TicketsToBook) as S
on T.FlightID = S.FlightID
and T.TicketsMax > (T.TicketsBooked + S.TicketsToBook)
when matched then
update set T.TicketsBooked = T.TicketsBooked + S.TicketsToBook
when not matched then
insert (TicketsMax, TicketsBooked)
values(S.TicketsToBook, S.TicketsToBook);
select * from Bookings
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 resulta en una clave duplicada / ya existe en la tabla.
Esto es algo que recientemente tuve que hacer:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[cjso_UpdateCustomerLogin]
(
@CustomerID AS INT,
@UserName AS VARCHAR(25),
@Password AS BINARY(16)
)
AS
BEGIN
IF ISNULL((SELECT CustomerID FROM tblOnline_CustomerAccount WHERE CustomerID = @CustomerID), 0) = 0
BEGIN
INSERT INTO [tblOnline_CustomerAccount] (
[CustomerID],
[UserName],
[Password],
[LastLogin]
) VALUES (
/* CustomerID - int */ @CustomerID,
/* UserName - varchar(25) */ @UserName,
/* Password - binary(16) */ @Password,
/* LastLogin - datetime */ NULL )
END
ELSE
BEGIN
UPDATE [tblOnline_CustomerAccount]
SET UserName = @UserName,
Password = @Password
WHERE CustomerID = @CustomerID
END
END
Estoy escribiendo mi solución. mi método no es "si" o "fusionar". mi metodo es facil
INSERT INTO TableName (col1,col2)
SELECT @par1, @par2
WHERE NOT EXISTS (SELECT col1,col2 FROM TableName
WHERE col1=@par1 AND col2=@par2)
Por ejemplo:
INSERT INTO Members (username)
SELECT ''Cem''
WHERE NOT EXISTS (SELECT username FROM Members
WHERE username=''Cem'')
Explicación:
(1) SELECCIONE col1, col2 DE TableName DONDE col1 = @ par1 Y col2 = @ par2 Selecciona de los valores buscados de TableName
(2) SELECCIONE @ par1, @ par2 DONDE NO EXISTE Toma si no existe desde (1) subconsulta
(3) Inserciones en los valores de paso de TableName (2)
Finalmente pude insertar una fila, con la condición de que no existiera, usando el siguiente modelo:
INSERT INTO table ( column1, column2, column3 )
(
SELECT $column1, $column2, $column3
WHERE NOT EXISTS (
SELECT 1
FROM table
WHERE column1 = $column1
AND column2 = $column2
AND column3 = $column3
)
)
que encontré en:
La solución completa está debajo (incluida la estructura del cursor). Muchas gracias a Cassius Porcus por el begin trans ... commit
código de publicación anterior.
declare @mystat6 bigint
declare @mystat6p varchar(50)
declare @mystat6b bigint
DECLARE mycur1 CURSOR for
select result1,picture,bittot from all_Tempnogos2results11
OPEN mycur1
FETCH NEXT FROM mycur1 INTO @mystat6, @mystat6p , @mystat6b
WHILE @@Fetch_Status = 0
BEGIN
begin tran /* default read committed isolation level is fine */
if not exists (select * from all_Tempnogos2results11_uniq with (updlock, rowlock, holdlock)
where all_Tempnogos2results11_uniq.result1 = @mystat6
and all_Tempnogos2results11_uniq.bittot = @mystat6b )
insert all_Tempnogos2results11_uniq values (@mystat6 , @mystat6p , @mystat6b)
--else
-- /* update */
commit /* locks are released here */
FETCH NEXT FROM mycur1 INTO @mystat6 , @mystat6p , @mystat6b
END
CLOSE mycur1
DEALLOCATE mycur1
go
Pase sugerencias de updlock, rowlock, holdlock cuando se prueba la existencia de la fila.
begin tran /* default read committed isolation level is fine */
if not exists (select * from Table with (updlock, rowlock, holdlock) where ...)
/* insert */
else
/* update */
commit /* locks are released here */
La sugerencia de bloqueo de actualización obliga a la consulta a tomar un bloqueo de actualización en la fila si ya existe, lo que evita que otras transacciones lo modifiquen hasta que 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 confirme o retroceda.
La sugerencia de bloqueo de fila obliga a bloquear la granularidad en el 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 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 llevan a ellos. La invocación de begin tran no le otorga inmunidad contra otra transacción al bloquear los bloqueos de algo antes de que llegue a ella. Debe intentar y factorizar su SQL para mantener los bloqueos durante el menor tiempo posible, confirmando la transacción tan pronto como sea 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 hash interno en SQL Server está degenerado para valores de 64 bits (valores de clave diferentes pueden ser hash para el mismo id de bloqueo).
Usted podría utilizar la funcionalidad de MERGE para lograr. De lo contrario puedes hacer:
declare @rowCount int
select @rowCount=@@RowCount
if @rowCount=0
begin
--insert....
INSERT INTO [DatabaseName1].dbo.[TableName1] SELECT * FROM [DatabaseName2].dbo.[TableName2]
WHERE [YourPK] not in (select [YourPK] from [DatabaseName1].dbo.[TableName1])
INSERT INTO table ( column1, column2, column3 )
SELECT $column1, $column2, $column3
EXCEPT SELECT column1, column2, column3
FROM table