为了把数据库中当前表中的下一行数据中的一项值更新到上一行的另一个项中,前几天下载了2870支股票的日交易数据,每支股有17年,差不多有4000多行数据,为了更好的预测第二天的股票趋势,要把第二天的收盘价数据存入上一天的一个项里,以方便预测程序调用。写这个存储过程的主要目的就是分析股票,写一下一个存储过程应该怎么写,也算分享一点自已的技术心得.

使用MySQL Workbench写的,用这个工具在数据库里加存储过程的步骤入下:
1.先选择一个数据库.存储过程只能真对数据库来保存.


2.选择创建存储过程项.




我写的这个存储过程,主要功能是把数据表中的下一行中某项值保存到上一行的另一项当中.存储过程有一个参数,就是要操作的数据表名,因为mysql不支持数据表作为参数,所以要使用prepare stmt from @p这个方法.@p是使用mysql的字符串拼接函数拼出一个字符串的sql语句,然后再用prepare把字符串转成sql命令,再使用execute执行这个命令.


CREATE DEFINER=`tfuser`@`%` PROCEDURE `updateTom`(in temp1 VARCHAR(30) )


BEGIN


DECLARE tabname VARCHAR(30);


    set tabname = temp1;


    set @minid = 0;


    set @maxid = 0;


    set @findFClose = 0.0;


    SET @STMT :=CONCAT("select id into @minid from `",tabname,"` where id=(select min(id) from `",tabname,"`);");   


    PREPARE STMT FROM @STMT;   


    EXECUTE STMT;


    SET @STMT :=CONCAT("select id into @maxid from `",tabname,"` where id=(select max(id) from `",tabname,"`);");   


    PREPARE STMT FROM @STMT;   


    EXECUTE STMT;


-- select id into minid from text where id=(select min(id) from text);


    -- select id into maxid from text where id=(select max(id) from text);


    


    WHILE @minid < @maxid DO   


SET @STMT :=CONCAT("SELECT fclose into @findFClose from `",tabname,"` where id=@minid+1;");   


PREPARE STMT FROM @STMT;   


EXECUTE STMT;


        SET @STMT :=CONCAT("update `",tabname,"` set tomorrow=@findFClose where id=@minid; ");   


PREPARE STMT FROM @STMT;   


EXECUTE STMT;


-- SELECT fclose into findFClose from shares_dat.text where id=(minid+1);


        -- update text set tomorrow=findFClose where id=minid; 


        SET @minid = @minid+1;   


    END WHILE; 


END





使用execute其实是有一个技巧的,有一个using 的方法,可以使用变量替换字符串中的?符号.请看下边例子:


以下例子显示了预备一个语句的两种方法。该语句用于在给定了两个边的长度时,计算三角形的斜边。

第一个例子显示如何通过使用文字字符串来创建一个预制语句,以提供语句的文本:


mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';


mysql> SET @a = 3;


mysql> SET @b = 4;


mysql> EXECUTE stmt1 USING @a, @b;


+------------+


| hypotenuse |


+------------+


|          5 |


+------------+


mysql> DEALLOCATE PREPARE stmt1;


第二个例子是相似的,不同的是提供了语句的文本,作为一个用户变量:


mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';


mysql> PREPARE stmt2 FROM @s;


mysql> SET @a = 6;


mysql> SET @b = 8;


mysql> EXECUTE stmt2 USING @a, @b;


+------------+


| hypotenuse |


+------------+


|         10 |


+------------+


mysql> DEALLOCATE PREPARE stmt2;


预制语句的SQL语法不能被用于带嵌套的风格中。也就是说,被传递给PREPARE的语句本身不能是一个PREPARE, EXECUTE或DEALLOCATE PREPARE语句。



写好后,可以使用call调用该存储过程.


call updateTom('000001');


运行效果很好.


存储过程写好了,然后就是运行命令了。


一共有2870个数据表,每个表都需要调用一次call updateTom()存储过程.就写了一个脚本,把这2870个命令都列在里边,保存为.sql文件。使用scp将sql文件上传到服务器。使用下边方法运行:


nohup mysql -hlocalhost -P3306 -uroot -pPw123456 -Dshares_dat < /home/ubuntu/download/db/updateother.sql > /home/ubuntu/download/db/sqllog.txt 2>&1 &

粗算了一下,每张数据表差不多要5秒钟时间,2870个数据表,差不多要用4个小时。所以最好就是用上边的后台运行方法执行这个sql文件。