付款单上的自定义自动增量

时间:2011-03-30 14:15:06

标签: php mysql

我们正在构建一个具有以下结构的表(payment_slip)......

+------+------+-------------+-------------+----------+---------------------+
| id   |      | recipt_code | prodcuct    | user     | dnt                 |
+------+------+-------------+-------------+----------+---------------------+
| 4    |      | 2011/1      | ABC         | tester   | 2011-02-17 23:36:12 |
+------+------+-------------+-------------+----------+---------------------+

我们希望通过使用自动增量添加字段recipt_code,因为它应该是唯一的,并且通过适当的系列如2011/1 2011/2 2011/3 2011/4,那么实现这一目标的最佳方法是什么?请帮助,谢谢。

4 个答案:

答案 0 :(得分:1)

首先,您不能拥有2个具有相同名称的列(idid)。您可以使用BEFORE触发器,特别是BEFORE INSERT来实现所需的结果:

DELIMITER $$$
CREATE TRIGGER YourTableBeforeINsert BEFORE INSERT ON YourTable
FOR EACH ROW
BEGIN      
   DECLARE prev_num UNSIGNED INT;
    // calculate your new_code
    SELECT MAX(CAST(SUBSTRING_INDEX(receipt_code,'_',-1) AS UNSIGNED)) INTO prev_num 
    FROM YourTable
    WHERE YEAR(dnt) = YEAR(new.dnt);
    IF (prev_num IS NULL) THEN
      SET prev_num = 1;
    ELSE 
      SET prev_num = prev_num+1;
    END IF;
    SET new.receipt_code = CONCAT(YEAR(new.dnt),'_',prev_num); 
END
$$$

<强>更新
  我添加了一个生成新收据编号的代码(Year +'_'+ Number)。我相信它应该可行,但我没有测试它。

答案 1 :(得分:1)

编辑2:

试试这段代码。新的'id'生成包含在函数generate_recipt_code 中,因此您可以直接在脚本或php中从INSERT语句中调用此函数。

CREATE TABLE payment_slip(
  id INT(11) NOT NULL AUTO_INCREMENT,
  recipt_code VARCHAR(255) DEFAULT NULL,
  prodcuct VARCHAR(255) DEFAULT NULL,
  user VARCHAR(255) DEFAULT NULL,
  dnt DATETIME DEFAULT NULL,
  PRIMARY KEY (id)
);

DELIMITER $$

CREATE FUNCTION generate_recipt_code()
RETURNS VARCHAR(255) CHARSET latin1
BEGIN
  DECLARE new_recipt_code VARCHAR(255);

  SET @date = NOW();
  SET @year = IF(MONTH(@date) < 4, YEAR(@date) - 1, YEAR(@date));
  SELECT
    COALESCE(
    CONCAT(@year, '/', MAX(SUBSTRING_INDEX(recipt_code, '/', -1) * 1) + 1),
    CONCAT(@year, '/1')
    )
  INTO
    new_recipt_code
  FROM
    payment_slip
  WHERE
    SUBSTRING_INDEX(recipt_code, '/', 1) = @year;

  RETURN new_recipt_code;
END
$$

DELIMITER ;

INSERT INTO payment_slip VALUES(NULL, generate_recipt_code(), 'ABC', 'tester', '2011-02-17 23:36:12');

PHP代码:

$mysqli = new mysqli('host_name', 'user_name', 'user_password', 'db_name', '3306');

$prodcuct = 'product1';
$user = 'user1';
$dnt = '2011-04-01 12:00:00';

$sql="INSERT INTO payment_slip VALUES(NULL, generate_recipt_code(), '$prodcuct', '$user', '$dnt')";
$mysqli->query($sql);

答案 2 :(得分:0)

您可以将id列(我假设已经自动递增)列为收据代码,如下所示:

SELECT CONCAT(DATE_FORMAT(dnt, '%Y'), '/', id) AS recipt_code
FROM `table_name`

当然,您假设收据代码中的2011是交易年份(dnt列)。

答案 3 :(得分:0)

一种相当讨厌的方法是使用LOCK TABLE,然后在PHP端生成新代码,插入新记录,然后再次解锁表。这是令人讨厌的,笨重的,如果你经常这样做会让你陷入并发麻烦,但它确实有效。

示例代码(未经测试):

$db->sql('LOCK TABLE payment_slip WRITE');
$row = $db->sql('SELECT recipt_code FROM payment_slip ORDER BY CAST(SUBSTR(recipt_code, 5), UNSIGNED) DESC LIMIT 0,1');
$next_num = intval(substr($row['recipt_code'], 5)) + 1;
$next_code = date('Y') . '/' . $next_num;
$db->sql('INSERT INTO payment_slip VALUES (?, ?, ...)', array(...));
$db->sql('UNLOCK TABLES');

或者,您可以将最高的代码存储在单独的表中。这有两个好处。首先,您不需要对整行进行排序以找到最高值。其次,即使删除行(例如,代码值最高的行),它也会继续工作。仍需要锁才能使其成为原子。此示例假定有一个名为config的简单key-&gt;值表。

$db->sql('LOCK TABLE payment_slip WRITE, config WRITE');
$row = $db->sql('SELECT value FROM config WHERE key = ?', 'max_recipt_code');
$next_num = intval(substr($row['value'], 5)) + 1;
$next_code = date('Y') . '/' . $next_num;
$db->sql('UPDATE config SET value = ? WHERE key = ?', $next_code, 'max_recipt_code');
$db->sql('INSERT INTO payment_slip VALUES (?, ?, ...)', array(...));
$db->sql('UNLOCK TABLES');