我们正在构建一个具有以下结构的表(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,那么实现这一目标的最佳方法是什么?请帮助,谢谢。
答案 0 :(得分:1)
首先,您不能拥有2个具有相同名称的列(id
和id
)。您可以使用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');