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? 这段代码在高并发下无论如何都会失败。你为什么不像你应该使用的那样使用IDENTITYSEQUENCE,为什么要重新发明***? 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 可以用作表列的默认约束,与使用 IDENTITYAUTO_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 显示顺序值

SQL SERVER 分页查询 和 Inser 添加并返回Id

SQL Server将一列拆分成多列

SQL Server 中 MIN/MAX 的更快替代方案

复制 SQL Server 表并添加和重新排列列

SQL Server如何去掉某个用户的select * 权限