根据年份生成唯一和顺序的交易 ID


Generating Unique and Sequential Transaction ID based on Year

我有一个生成唯一事务ID的php应用程序。但是,我发现有时,两个事务具有相同的ID。 下面是我的代码。如果我能在给定两个交易相同的传输时知道原因,我将不胜感激。另外,我希望在新的一年开始时从 1 开始计数。我不知道该怎么做。

对于问题 1:

<?php 
$db = mysqli_query($connection,"SELECT * FROM tab_requisition");
$nrw = mysqli_num_rows($db);
$refID= ("NR".date("Y").($nrw+1));?>
   <tr>
   <th>Requisition ID:</th>
  <td><input  type="text" name="refid" value="<?php echo $refID;?>"  size="100"  readonly="readonly"/></td></tr>

对于问题 2:我怎样才能使上述$refID在每年年初从 1 开始计数。像NR20161,NR20162.....NR20165000。假设在 2016 年 12 月 31 日结束时,最后一个 id 是 NR20165000。我希望下一个从NR20171开始NR20172,......NR2017XXXXX

我将不胜感激任何关于如何防止上述重复并在每年年初重置的回复。

$nrw = mysqli_num_rows($db);
$refID= ("NR".date("Y").($nrw+1));?>

这是绝对的不。如果有一天删除行怎么办?您的下一个ID将下降,但它已经存在,这就是您收到该错误的原因。

不能使用行计数来有效地决定下一个数字应该是什么。

您可以简单地为此使用自动递增值,您的RDBMS将处理冲突。然后,您可以使用该自动递增值生成字母数字唯一 ID。

为此,使用以下列创建您自己的表"数字组":

  • 年份:整数
  • 下一个数字: 整数

与主键在年。

如果随后想要获取一年的下一个数字,请使用以下 SQL 查询:

insert into NumberGroups(Year, NextNumber) values (2016, LAST_INSERT_ID(1) + 1) on duplicate key update NextNumber = LAST_INSERT_ID(NextNumber) + 1; 
select LAST_INSERT_ID();

在一次调用中执行此操作,mysqli_query()将 2016 替换为您想要计数器的年份。然后,这将返回要使用的下一个免费号码,从每年的 1 开始。

它的作用:

它检查表中是否已有给定年份的行。如果给定年份没有行,则会插入一个值为 2 的新行作为 NextNumber,并将 LAST_INSERT_ID() 设置为 1。如果给定年份已经有一行,则更新现有行,并将该行的 NextNumber 增加 1,同时记住 LAST_INSERT_ID() 中 NextNumber 的旧值。最后,我们在 LAST_INSERT_ID() 中设置的值返回给调用方。

当前方法中的问题是,当多个操作并行运行时,两个操作可以读取表中的相同行计数。如果需要唯一的计数器,则必须确保并行运行的两个活动不会读取相同的值。您可以通过使用具有正确隔离级别的事务来执行此操作,也可以通过读取当前值并将其递增到同一个 SQL 语句中来执行此操作(如在此变体中)。

资源:

  • 在重复密钥更新时插入
  • LAST_INSERT_ID()

补充一下Hanky Panky的答案。

注意:以下代码未测试

year列添加到数据库表(以及自动递增的唯一 ID),

当交易实际发生时:

INSERT INTO `tab_requisition` (year, ...) VALUES(YEAR(NOW()), ...)

捕获交易/记录的真实唯一ID

$ID = mysqli_insert_id ($db);

获取当前年度记录计数:

SELECT COUNT(*) FROM `tab_requisition` WHERE `year` = YEAR(NOW()) 
-- below line should take care of raise condition (if another record was added meanwhile)
AND `id` <= '.$ID

生成您的序列号/参考编号

$prefix = 'NR';
$year = date('Y');
$count = str_pad($year_record_count,6,'0', STR_PAD_LEFT);
$refNum = $year . $count;

最后,用您的refNum更新您的记录:

UPDATE `tab_requisition` SET `ref_num` = "'.$refNum.'" WHERE id = '.$ID

str_pad用于将计数填充到特定长度,这将为排序等生成正确的编号。

而不是

NR20171
NR20172
NR201712
NR2017137

它会变成

NR2017000001
NR2017000002
NR2017000012
NR2017000137

我知道,这需要多次数据库调用,但它可能为您工作,具体取决于服务器负载/流量