【问题标题】:How to generate a sequential number that restarts yearly in a web application如何在 Web 应用程序中生成每年重新启动的序列号
【发布时间】:2022-01-15 21:20:33
【问题描述】:

我需要生成一个由任意前缀、年份和递增数字组成的代码。递增的数字必须在当年第一次生成数字时从 1 开始。

此代码需要添加到 sqlite 数据库并在 PHP 脚本的其他地方可用。

我现在所做的使用 4 次访问数据库:

    $codePrefix = 'TEST';
    
    $stmt = $db->prepare(
        'INSERT INTO test (year)
         VALUES(strftime("%Y", "now"))'
    );
    
    $stmt->execute();
    
    $id = $db->lastInsertId();
    
    $stmt = $db->prepare('SELECT `year` FROM `test` WHERE `id`=:id');
    
    $stmt->bindValue(':id', $id);
    
    $stmt->execute();
    
    $result = $stmt->fetch(PDO::FETCH_ASSOC);
    $year = $result['year'];
    
    $stmt = $db->prepare('SELECT Ifnull(Max(id), 0) `max_id` FROM `test`
     WHERE `year`<:year');
    
    $stmt->bindValue(':year', $year);
    
    $result = $stmt->execute();
    
    $result = $stmt->fetch(PDO::FETCH_ASSOC);
    $previousMax = $result['max_id'];
    
    $codeSuffix = $id-$previousMax;
    
    $code = "{$codePrefix}-{$year}-{$codeSuffix}";
    
    $stmt = $db->prepare('UPDATE `test` SET `code`=:code WHERE `id`=:id');
    
    $stmt->bindParam(':code', $code);
    $stmt->bindParam(':id', $id);
    
    $stmt->execute();

我在这里滥用id 是整数主键和自动增量的事实。

这行得通。但我觉得它正在以非常复杂的方式做一些非常简单的事情。

有没有更好的解决方案?我需要假设一月一日的午夜可能发生在代码的任何时刻,所以我不能在不访问数据库的情况下从 PHP 获取年份信息。

在有人问之前,即使没有绑定任何值,我也使用准备好的语句的原因是因为稍后显然会有更多的数据插入到表中。

【问题讨论】:

  • 没有人会因为你总是使用准备好的语句而责备你!几乎每次我看到对没有间隙或带有前缀重复的顺序模式的要求时,它都是为了解决显示或输出问题,而不应该也不应该由数据库直接处理。今年数据库中的第一项只是查询的结果,它可以被称为1,而无需存储它。所以在你仔细阅读这个之前,我真的会仔细检查你是否真的需要这个。
  • @ChrisHaas 我确定我需要它。代码实际上是我需要的,而不是需要代码来解决另一个问题。这与输出问题无关(我什至没有想到)。
  • @ChrisHaas 差距会让我心烦意乱,但如果它们很少存在,我会接受它们作为生活中的事实。在我实现它的方式中,只有在手动删除条目时才会出现差距。我绝对可以忍受。
  • 你能做到{$prefix}-{$year}-{$dayOfYear}-{$num} num 是一个整数但不一定是连续的吗?即,只需使用 unix 时间戳,然后您就可以在插入时生成 id。
  • 另请注意,如果您将下一条记录的 ID 基于最后一条记录的 SELECT 的结果,那么您将在运行多个线程时引入重复 ID 的可能性。

标签: php sqlite


【解决方案1】:

考虑使用 ROW_NUMBER 窗口函数的纯 SQL 解决方案。下面分配给新字段,new_id

UPDATE test
SET new_id = 'TEST_' || test.[Year] || '_' || sub.rn
FROM (
    SELECT id,
        [Year],
        ROW_NUMBER() OVER (PARTITION BY [Year] ORDER BY id) AS rn
    FROM test
) AS sub
WHERE test.id = sub.id;

【讨论】:

  • 我真的很喜欢这个,刚刚测试了一下,它会将数据库访问次数减少到3,插入初始数据,更新,然后选择代码(什么你打电话给new_id)。如果这里没有更好的东西,我会接受这个作为答案。
  • 一个小注释,Year 列在它使用的第一个上下文中是模棱两可的。当然我会WHERE test.id=:id AND sub.id=:id,因为我不想覆盖以前生成的代码。
  • 考虑为 newid 添加一个新的文本列,它会定期更新并避免使用 PHP 参数。如果行被删除或年份更改,此窗口计算可以返回不同的结果。因此,在每个附加的行之后运行。顺便说一句 - SQLite 始终在表上维护唯一的 rowid 系统变量。
  • 另外,不确定您所说的 Year 含糊不清是什么意思,因为您的问题是要求按年份顺序编号。如果这是计算的,请相应地替换。因此,您可能需要根据自己的需要进行调整。
  • 应该是SET new_id = 'TEST_' || test.[Year] || '_' || sub.rn
猜你喜欢
  • 2018-12-15
  • 1970-01-01
  • 1970-01-01
  • 2021-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-25
  • 2014-08-27
相关资源
最近更新 更多