SQL Server SELECT MAX 并添加 1
Posted
技术标签:
【中文标题】SQL Server SELECT MAX 并添加 1【英文标题】:SQL Server SELECT MAX and Add 1 【发布时间】:2021-12-06 22:08:20 【问题描述】:以下 C# 代码正确使用 mysql 服务器从表中获取列的 MAX 值,同时此查询将值加 1,如下所示:
SqlDataReader dr = new SqlCommand("SELECT (MAX(Consec) +1) AS NextSampleID FROM Samples", Connection).ExecuteReader();
while (dr.Read())
//in case of Maximum value of Consec = 555, the expected result: A556
txtSampleID.Text = "A" + dr["NextSampleID"].ToString();
但是,在将数据库从 MySQL 迁移到 SQL Server 后,此代码不再起作用,如果 MAX(Consec) = 555 运行查询后的结果是 A555,则结果相同,它不会像以前那样添加 1 使用MySQL 服务器。
问题:获取Consec的MAX值的正确查询是什么以及如何在同一个查询中将MAX的结果加“1”?
【问题讨论】:
我没有发现查询有任何问题。你确定 Max(Consec) = 555 而不是 554? 这段代码在高并发下无论如何都会失败。你为什么不像你应该使用的那样使用IDENTITY
或SEQUENCE
,为什么要重新发明***?
However this code does not work anymore after migrating the DB from MySQS to MS SQL
错误,此代码根本没有用。它避免问题的唯一方法是因为它很少使用——记录没有被删除,一次只有一个人尝试插入数据
【参考方案1】:
MySQL 查询是错误的,除了在琐碎的应用程序中不起作用,只有一个用户,没有删除和没有关系:
并发调用会产生相同的 MAX 值,因此会产生相同的重复值 删除记录将减少 MAX 值,从而导致将以前的 ID 值分配给新行。如果该 ID 值在另一个表中使用,则新记录最终将与它没有实际关系的行相关联。这可能非常糟糕。想象一下,一名患者的测试样本与另一名患者的样本混合在一起。 计算 MAX 需要锁定整个表或索引,从而阻塞或被其他人阻塞。不过,鉴于 MySQL 的 MVCC 隔离,这并不能防止重复,因为并发SELECT MAX
查询不会相互阻塞。
MAX+1
可能会在只有一个终端生成发票编号的 POS 应用程序中工作,但一旦添加了两个 POS 终端,您就有可能生成重复发票。
另一方面,在电子商务应用程序中,几乎可以保证即使每月只下两个订单,它们也会在完全相同的时刻发生,从而导致重复。
正确的 MySQL 解决方案和等效方案
MySQL中正确的解决方案是使用AUTO_INCREMENT属性:
CREATE TABLE Samples (
Consec INT NOT NULL AUTO_INCREMENT,
...
);
如果您希望发票编号包含其他数据,请使用计算列来组合递增编号和其他数据。
SQL Server 中的等价物是IDENTITY property:
CREATE TABLE Samples (
Consec INT NOT NULL IDENTITY,
...
);
序列
SQL Server 和其他数据库中的另一个可用选项是SEQUENCE 对象。 SEQUENCE 可用于生成不绑定到表的递增数字。它也可以重置,非常适合在特定时期(例如每年)之后重置发票编号的会计应用程序。
由于SEQUENCE
是一个独立的对象,您可以在使用NEXT VALUE FOR 在数据库中插入任何数据之前递增并接收新值,例如:
SELECT NEXT VALUE FOR seq_InvoiceNumber;
NEXT VALUE FOR
可以用作表列的默认约束,与使用 IDENTITY
或 AUTO_INCREMENT
的方式相同:
Create MyTable (
...
Consec INT NOT NULL DEFAULT (NEXT VALUE FOR seq_ThatSequence)
)
多表序列
多个表可以使用相同的顺序。一种有用的情况是将文档 ID 分配给从多个来源导入、存储在不同表中的数据,例如付款。
支付提供商(信用卡、银行等)使用不同格式发送对帐单。显然,您不能在那里丢失任何信息,因此您需要为每个提供商使用不同的表,但仍然能够以相同的方式处理付款,无论它们来自哪里。
如果您在每张桌子上使用IDENTITY
,您最终会得到来自不同提供商的付款的 ID 冲突。例如,在 OrderPayments 表上,您必须同时记录提供商名称 和 ID。生成单一的付款视图最终会产生无法自行使用的 ID 值。
不过,通过使用单个 SEQUENCE,每条记录都会获得自己的 ID,无论表如何。
【讨论】:
以上是关于SQL Server SELECT MAX 并添加 1的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server:SELECT 查询以获取 DISTINCT 和 MAX 显示顺序值