我需要编写一个T-SQL存储过程来更新表中的行.如果该行不存在,请插入它.所有这些步骤都由事务包装.
这是一个预订系统,所以它必须是原子和可靠的.如果交易已提交且预订航班,则必须返回true.
我是T-SQL的新手,不知道如何使用@@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 …Run Code Online (Sandbox Code Playgroud) 我想做一些快速插入,但避免重复到表中.为了论证,我们称之为MarketPrices,我一直在尝试两种方法,但不确定如何更快地进行基准测试.
INSERT INTO MarketPrices (SecurityCode, BuyPrice, SellPrice, IsMarketOpen)
SELECT @SecurityCode, @BuyPrice, @SellPrice, @IsMarketOpen
EXCEPT
SELECT SecurityCode, BuyPrice, SellPrice, j.bool as IsActive FROM MarketPrices
CROSS JOIN (SELECT 0 as bool UNION SELECT 1 as bool ) as j
Run Code Online (Sandbox Code Playgroud)
要么
DECLARE @MktId int
SET @MktId = (SELECT SecurityId FROM MarketPrices
where SecurityCode = @SecurityCode
and BuyPrice=@BuyPrice
and SellPrice = @SellPrice)
IF (@MktId is NULL)
BEGIN
INSERT INTO MarketPrices (SecurityCode, BuyPrice, SellPrice, IsMarketOpen)
VALUES
(@SecurityCode,@BuyPrice, @SellPrice, @IsMarketOpen)
END
Run Code Online (Sandbox Code Playgroud)
假设这@whatever是存储过程中的输入参数.
我希望能够在BuyPrice或SellPrice或两者与之前的其他所有事件不同时为每个SecurityCode插入新记录.我不关心IsMarketOpen.
关于上述任何一种方法,有什么明显的愚蠢之处吗?一个比另一个快吗?
如何通过选择插入时插入表格之前如何检查重复项:
insert into table1
select col1, col2
from table2
Run Code Online (Sandbox Code Playgroud)
我需要检查table1是否已经有一行table1.col1.value = table2.col1.value,如果是,则从插入中排除该行.
我发出一个单独的SQL查询,包含使用UNION分组的多个SELECT:
SELECT *
FROM employee
LEFT JOIN department
ON employee.DepartmentID = department.DepartmentID
UNION
SELECT *
FROM employee
RIGHT JOIN department
ON employee.DepartmentID = department.DepartmentID;
Run Code Online (Sandbox Code Playgroud)
假设我在READ_COMMITTED事务隔离下执行此查询,两个SELECT语句是否保证以原子方式执行?或者我是否存在各个SELECT语句之间数据更改的风险?SQL规范是否讨论过这种事情?
澄清:当我说"原子"时,我不是指ACID中的"A".我的意思是我希望在查询完成之前对department和employee表进行读锁定.
我有一个表,用于记录用户操作.每次执行操作时,值都需要增加.由于用户可以同时拥有多个会话,因此该过程需要是原子的,以避免多用户问题.
该表有3列:
ActionCode 如 varcharUserID 如 intCount 如 int我想通过ActionCode和UserID到将添加一个新行,如果一个已经不存在,并设置数量为1.如果该行确实存在一个功能,它只是一个增加数量. ActionCode并UserID组成此表的主要唯一索引.
如果我需要做的就是更新,我可以做这样简单的事情(因为UPDATE查询已经是原子的):
UPDATE (Table)
SET Count = Count + 1
WHERE ActionCode = @ActionCode AND UserID = @UserID
Run Code Online (Sandbox Code Playgroud)
我是SQL新手中的原子事务.这个问题可能已在多个部分得到解答,但我找不到这些问题并将这些部分放在一个解决方案中.这也需要非常快,而不会变得复杂,因为这些操作可能经常发生.
编辑:对不起,这可能是MySQL的一个骗局如何在单个查询中执行if exists增量.我搜索了很多,但tsql在我的搜索中,一旦我改为sql相反,这是最好的结果.如果这是原子的,那不是很明显,但很确定它会是.我可能会投票删除这个作为欺骗,除非有人认为这个问题和答案可以增加一些新的价值.
我已经阅读了很多关于防止竞争条件的内容,但通常在upsert场景中有一条记录.例如: SQL Server 2005中的Atomic UPSERT
我有不同的要求,它是为了防止多行的竞争条件.例如,假设我有以下表结构:
GiftCards:
GiftCardId int primary key not null,
OriginalAmount money not null
GiftCardTransactions:
TransactionId int primary key not null,
GiftCardId int (foreign key to GiftCards.GiftCardId),
Amount money not null
Run Code Online (Sandbox Code Playgroud)
可能有多个进程插入GiftCardTransactions,我需要阻止插入,如果SUM(GiftCardTransactions.Amount) + insertingAmount将继续GiftCards.OriginalAmount.
我知道我可以使用TABLOCKX的GiftCardTransactions,但很明显,对于很多的交易,这将是不可行的.另一种方法是添加一个GiftCards.RemainingAmount列,然后我只需要锁定一行(虽然可能会锁定升级),但不幸的是,这对我来说不是一个选项(这是最好的选择吗?).
可能答案只是插入,然后选择SUM(GiftCardTransactions.Amount),并在必要时回滚,而不是试图阻止插入.这是一个边缘情况,所以我不担心不必要地使用PK值等.
所以问题是,如果不修改表结构并使用事务,隔离级别和提示的任何组合,我如何通过最小量的锁定来实现这一点?
我们有一个更新数据库的进程,它使用以下SQL
IF NOT EXISTS (SELECT * FROM Target_Table WHERE Target_Table_ID = ...)
BEGIN
INSERT ...
END
ELSE
BEGIN
UPDATE ...
END
Run Code Online (Sandbox Code Playgroud)
我想改变它以使用一个MERGE语句,以避免可能的竞争条件,其中单独评估IF和然后INSERT或UPDATE语句.
但是,只要我执行查询,我就会收到错误:
MERGE语句的目标表'Target_Table'不能具有任何已启用的规则.找到规则'TargetTable_RULE'
我理解文档声明该表不能启用规则,虽然我在第一次阅读时错过了它,除了在执行之前禁用规则MERGE(我不认为这是一个可行的解决方案),似乎我坚持该IF NOT EXISTS解决方案.
该文件没有解释的是为什么目标表不允许有规则.在我的情况下,规则是> 0对值的简单检查.
有谁知道为什么在这种情况下不允许规则,是否有另一种方式以原子方式执行upsert?
编辑:正如Andriy M评论的问题SQL Server 2005中的Atomic UPSERT已经有大量关于原子upserts的信息,所以我不会在这里重复讨论.相反,我只想知道为什么MERGE语句无法在已定义规则的表上执行,是否有解决方法?
我有一个流程,我不想跟踪某些内容是创建还是更新.跟踪会很复杂.我想执行创建或更新.架构就像......
col1 varchar() (PK)
col2 varchar() (PK)
col3 varchar() (PK)
col4 varchar()
Run Code Online (Sandbox Code Playgroud)
我正在考虑做
TRY
{
INSERT ...
}
CATCH(DuplicateKeyException)
{
UPDATE ...
}
Run Code Online (Sandbox Code Playgroud)
你有什么建议?
我想确保我理解其他最高投票的答案.鉴于我的模式,UPDATE总是会发生(即使使用INSERT),但插入只发生在它不存在的地方?
//UPSERT
INSERT INTO [table]
SELECT [col1] = @col1, [col2] = @col2, [col3] = @col3, [col4] = @col4
FROM [table]
WHERE NOT EXISTS (
-- race condition risk here?
SELECT 1
FROM [table]
WHERE [col1] = @col1
AND [col2] = @col2
AND [col3] = @col3
)
UPDATE [table]
SET [col4] = @col4
WHERE [col1] = @col1 …Run Code Online (Sandbox Code Playgroud) 我意识到在这个相同的主题上有很多回答SO问题,但我似乎无法使用任何这些信息来弄清楚我的查询有什么问题.
我正在尝试将记录插入到我的表中,只有具有相同记录database_owner和database_name(我的两个列名称)的记录尚不存在.
我正在使用查询:
INSERT INTO users_databases (database_name, database_key, database_secret, database_owner)
VALUES ('DB1', '263f690d-7ac3-49f2-aa3b-f5672e4639a2', '367123d8-e5a7-46a0-8101-21f39e6ac8d9', 'x@x.com')
WHERE
NOT EXISTS
(SELECT database_name FROM uses_databases WHERE database_name = 'DB1' AND database_owner = 'x@x.com');
Run Code Online (Sandbox Code Playgroud)
但是我收到了错误 Incorrect syntax near the keyword 'WHERE'.
我还应该指出运行查询
SELECT database_name
FROM uses_databases
WHERE database_name = 'DB1' AND database_owner = 'x@x.com'
Run Code Online (Sandbox Code Playgroud)
确实会返回记录.
我哪里可能出错?从我在其他问题中看到的内容来看,这看起来是正确的.但显然不是.:-)任何建议都会非常有帮助.
我的代码中有以下声明
INSERT INTO #TProductSales (ProductID, StockQTY, ETA1)
VALUES (@ProductID, @StockQTY, @ETA1)
Run Code Online (Sandbox Code Playgroud)
我想做的事情如下:
IF @ProductID exists THEN
UPDATE #TProductSales
ELSE
INSERT INTO #TProductSales
Run Code Online (Sandbox Code Playgroud)
有没有办法可以做到这一点?