mysql使用触发器或函数实现自增序列

转自:http://foolraty.iteye.com/blog/777215

http://www.blogjava.net/Skynet/archive/2011/03/23/301847.html

http://sulong.me/2011/11/14/spring_mysql_sequence

MySQL This function has none of DETERMINISTIC, NO SQL...错误1418 的原因分析及解决方法

http://blog.csdn.net/ty_soft/article/details/6940190 

 

 

一、 单独的数据表+函数:

 如果你不想使用mysql的自动递增,但又想实现主键序列号的功能,可以使用下面的方法,通过函数用一张表去维护生成多个表的序列号,简单又实用

1.创建生成多个表的序列号的数据维护表

CREATE TABLE seq (
  name varchar(20) NOT NULL,
  val int(10) UNSIGNED NOT NULL,
  PRIMARY KEY  (name)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;

 

2.插入几条初始化数据

INSERT INTO seq VALUES('one',100);
INSERT INTO seq VALUES('two',1000);

 

3.创建函数以生成序列号

CREATE FUNCTION seq(seq_name char (20)) returns int
begin
 UPDATE seq SET val=last_insert_id(val+1) WHERE name=seq_name;
 RETURN last_insert_id();
end

 

4.测试

  1. mysql>   SELECT  seq ( 'one' ),seq ( 'two' ),seq ( 'one' ),seq ( 'one' );
  2. + ------------+------------+------------+------------+
  3. | seq ( 'one' )  | seq ( 'two' )  | seq ( 'one' )  | seq ( 'one' )  |
  4. + ------------+------------+------------+------------+
  5. |          102  |        1002  |          103  |          104  |
  6. + ------------+------------+------------+------------+
  7. 1  row   IN   SET   ( 0. 00  sec )


 

二、触发器

 
原理是在建立一个触发器TRIGGER tri_NewBH 在table插入时执行序列计算 
mysql> CREATE TABLE tb(BH CHAR(16),content VARCHAR(20),`date` DATETIME,val INT);
Query OK, 0 rows affected (0.05 sec)

mysql>
mysql>
mysql> DELIMITER $$
mysql> DROP TRIGGER IF EXISTS tri_NewBH $$
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql>
mysql> CREATE TRIGGER tri_NewBH BEFORE INSERT ON tb
    -> FOR EACH ROW
    -> BEGIN
    ->     DECLARE dt CHAR(8);
    ->     DECLARE bh_id CHAR(16);
    ->     DECLARE number INT;
    ->     DECLARE new_bh VARCHAR(16);
    ->
    ->     SET dt = DATE_FORMAT(CURDATE(),'%Y%m%d');
    ->
    ->     SELECT
    ->         MAX(BH) INTO bh_id
    ->     FROM tb
    ->     WHERE BH LIKE CONCAT(dt,'%');
    ->
    ->     IF bh_id = '' OR bh_id IS NULL THEN
    ->         SET new_bh = CONCAT(dt,'00000001');
    ->     ELSE
    ->         SET number = RIGHT(bh_id,8) + 1;
    ->         SET new_bh =  RIGHT(CONCAT('00000000',number),8);
    ->         SET new_bh=CONCAT(dt,new_bh);
    ->     END IF;
    ->
    ->     SET NEW.BH = new_bh;
    -> END$$
Query OK, 0 rows affected (0.09 sec)

mysql>
mysql> DELIMITER ;
mysql> INSERT INTO tb(content,`date`,val) VALUES('LiangCK','2009-05-11',20);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO tb(content,`date`,val) VALUES('LiangCK','2009-05-11',20);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO tb(content,`date`,val) VALUES('LiangCK','2009-05-11',20);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO tb(content,`date`,val) VALUES('LiangCK','2009-05-11',20);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO tb(content,`date`,val) VALUES('LiangCK','2009-05-11',20);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO tb(content,`date`,val) VALUES('LiangCK','2009-05-11',20);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO tb(content,`date`,val) VALUES('LiangCK','2009-05-11',20);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM tb;
+------------------+---------+---------------------+------+
| BH               | content | date                | val  |
+------------------+---------+---------------------+------+
| 2009051100000001 | LiangCK | 2009-05-11 00:00:00 |   20 |
| 2009051100000002 | LiangCK | 2009-05-11 00:00:00 |   20 |
| 2009051100000003 | LiangCK | 2009-05-11 00:00:00 |   20 |
| 2009051100000004 | LiangCK | 2009-05-11 00:00:00 |   20 |
| 2011051200000001 | LiangCK | 2009-05-11 00:00:00 |   20 |
| 2011051200000002 | LiangCK | 2009-05-11 00:00:00 |   20 |
| 2011051200000003 | LiangCK | 2009-05-11 00:00:00 |   20 |
+------------------+---------+---------------------+------+
7 rows in set (0.00 sec)
  

三、下面就是另外一个的实现方案: 

原理是创建一个专门记录序列的表sequence,记录有当前序列号,序列的间隔如+1

 

Sql代码    收藏代码
  1. DROP TABLE IF EXISTS sequence;/*创建记录当前序列的表*/  
  2. CREATE TABLE sequence (  
  3. name              VARCHAR(50) NOT NULL,  
  4. current_value INT NOT NULL,  
  5. increment       INT NOT NULL DEFAULT 1,  
  6. PRIMARY KEY (name)  
  7. ) ENGINE=InnoDB;  
  8. INSERT INTO sequence VALUES ('MovieSeq',3,5);  
  9. DROP FUNCTION IF EXISTS currval;  
  10. DELIMITER $/*创建一个获取当前序列的function*/  
  11. CREATE FUNCTION currval (seq_name VARCHAR(50))  
  12. RETURNS INTEGER  
  13. CONTAINS SQL  
  14. BEGIN  
  15.   DECLARE value INTEGER;  
  16.   SET value = 0;  
  17.   SELECT current_value INTO value  
  18.   FROM sequence  
  19.   WHERE name = seq_name;  
  20.   RETURN value;  
  21. END$  
  22. DELIMITER ;  

 测试一下结果:

 

 

Sql代码    收藏代码
  1. mysql> SELECT currval('MovieSeq');  
  2. +---------------------+  
  3. | currval('MovieSeq') |  
  4. +---------------------+  
  5. |                   3 |  
  6. +---------------------+  
  7. 1 row in set (0.00 sec)  
  8. mysql> SELECT currval('x');  
  9. +--------------+  
  10. | currval('x') |  
  11. +--------------+  
  12. |            0 |  
  13. +--------------+  
  14. 1 row in set, 1 warning (0.00 sec)  
  15. mysql> show warnings;  
  16. +---------+------+------------------+  
  17. Level   | Code | Message          |  
  18. +---------+------+------------------+  
  19. | Warning | 1329 | No data to FETCH |  
  20. +---------+------+------------------+  
  21. 1 row in set (0.00 sec)  

 nextval 

//获取下一个数值..先在 sequence里面调用update当前最大数值+1然后再调用 currval获得当前数值
Sql代码    收藏代码
  1. DROP FUNCTION IF EXISTS nextval;  
  2. DELIMITER $  
  3. CREATE FUNCTION nextval (seq_name VARCHAR(50))  
  4. RETURNS INTEGER  
  5. CONTAINS SQL  
  6. BEGIN  
  7.    UPDATE sequence  
  8.    SET          current_value = current_value + increment  
  9.    WHERE name = seq_name;  
  10.    RETURN currval(seq_name);  
  11. END$  
  12. DELIMITER ;  
  mysql> select nextval('MovieSeq');
Sql代码    收藏代码
  1. +---------------------+  
  2. | nextval('MovieSeq') |  
  3. +---------------------+  
  4. |                  15 |  
  5. +---------------------+  
  6. 1 row in set (0.09 sec)  
  7.   
  8. mysql> select nextval('MovieSeq');  
  9. +---------------------+  
  10. | nextval('MovieSeq') |  
  11. +---------------------+  
  12. |                  20 |  
  13. +---------------------+  
  14. 1 row in set (0.01 sec)  
  15.   
  16. mysql> select nextval('MovieSeq');  
  17. +---------------------+  
  18. | nextval('MovieSeq') |  
  19. +---------------------+  
  20. |                  25 |  
  21. +---------------------+  
  22. 1 row in set (0.00 sec)  
  setval 
Sql代码    收藏代码
  1. DROP FUNCTION IF EXISTS setval;  
  2. DELIMITER $  
  3. CREATE FUNCTION setval (seq_name VARCHAR(50), value INTEGER)  
  4. RETURNS INTEGER  
  5. CONTAINS SQL  
  6. BEGIN  
  7.    UPDATE sequence  
  8.    SET          current_value = value  
  9.    WHERE name = seq_name;  
  10.    RETURN currval(seq_name);  
  11. END$  
  12. DELIMITER ;  
  mysql> select setval('MovieSeq',150);
Sql代码    收藏代码
  1. +------------------------+  
  2. | setval('MovieSeq',150) |  
  3. +------------------------+  
  4. |                    150 |  
  5. +------------------------+  
  6. 1 row in set (0.06 sec)  
  7.   
  8. mysql> select curval('MovieSeq');  
  9. +---------------------+  
  10. | currval('MovieSeq') |  
  11. +---------------------+  
  12. |                 150 |  
  13. +---------------------+  
  14. 1 row in set (0.00 sec)  
  15.   
  16. mysql> select nextval('MovieSeq');  
  17. +---------------------+  
  18. | nextval('MovieSeq') |  
  19. +---------------------+  
  20. |                 155 |  
  21. +---------------------+  
  22. 1 row in set (0.00 sec)  
 

你可能感兴趣的:(数据库)