我需要编写一个T-SQL存储过程来更新表中的一行。如果该行不存在,则插入它。所有这些步骤都由一个事务包装。
这是一个预订系统,所以它必须是原子和可靠的。如果事务已提交且机票已预订,则必须返回true。
我确定如何使用@@rowcount。这就是我到目前为止所写的。我走的路对吗?
-- 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?)
这是我最近不得不做的事情:
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
这是我最近不得不做的事情:
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
我最终能够插入一行,在它不存在的情况下,使用以下模型:
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
)
)
我在:
http://www.postgresql.org/message-id/87hdow4ld1.fsf@stark.xeocode.com
完整解决方案如下(包括游标结构)。非常感谢卡修斯·波库斯开始翻译…提交上面发布的代码。
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
看一下MERGE命令。你可以在一条语句中执行UPDATE, INSERT和DELETE操作。
下面是一个使用MERGE的工作实现
-在更新之前检查航班是否已满,否则执行插入操作。
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
然后……
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