首先叙述一下我碰到的问题,如果这个讲不清楚,则有可能压根不知道这究竟有什么用,有些事情总是在碰到困难需要解决非用不可的时候印象才会更深刻。
这是一个转换工程,需要把dvbbs的access数据库转换成phpwind的MySQL形式。
phpwind论坛数据库,
表`pws_threads`存放主题(包括标题)
表`pws_posts` 存放着所有除了一楼之外的帖子,
表`pws_tmsgs`存放着主题第一楼的数据。
dvbbs的做法是将主题和回帖分开,主题用一个表存储,而所有回帖(包括第一楼)都存在另一个表里,楼层按顺序排列,标记为0的显然就是1楼,然后以此类推,它没有再单独开一个表存放所谓1楼数据。
这倒不麻烦,只需要将原表中相同主题ID并且回帖ID最小的抽出来,然后放到phpwind的pws_tmsgs里就行了,然后排除这些1楼的回帖,将余下的全部帖子都放进phpwind的`pws_posts`即可。
问题在,由于操作不当。在原数据库还没有排除所谓“1楼”帖子的情况下,又将他们导入了pws_posts,即在`pws_tmsgs里有一个“1楼”在,pws_posts里又出现了一个一模一样的“1楼”,最后每个主题都存在两个一模一样的“1楼”(第二楼内容和第一楼完全一样),这让人抓狂!
因为数据量较大,很不情愿再推倒重来一次,那么现在这个局面该怎么办?
1. 总的来说,删除现阶段的第二楼即可达到目的。
2. 如何找到第二楼的回帖序号?
3. 在一个主题序号(tid)下,有很多跟帖,这些跟帖以(pid)形式出现,则查出某tid下最小的pid,则是最老的回帖(即1楼),删除之即可。
4. 单纯用SQL语句已经做不到这一点了,因为tid返回的值是一个记录集,而我们必须再从这个记录集里寻找pid最小值并删除之,也许有SQL高人能靠纯查询做到,但实话说,我不行。
---------------------------
重点(全部亲测通过):
1. phpMyadmin中可以创建并执行存储过程。
2. mysql支持CURSOR(即游标)
3. MySQL不支持SELECT * INTO XXX这样的表复制,而需要
CREATE TABLE aaaa(id int) SELECT yyy FROM ttt
这样的变通方法完成。
方法:
1. 创建一个表aaaa,获取所有pid(主题号):
CREATE TABLE aaaa(tid int) SELECT tid FROM `pws_posts` group by tid order by tid
2. 创建一个存储过程,
DELIMITER $$
DROP PROCEDURE IF EXISTS TEST1$$
CREATE PROCEDURE TEST1()
BEGIN
DECLARE tidv INT;
DECLARE pidv INT;
DECLARE fig INT;
DEClARE cur CURSOR FOR Select tid From `aaaa`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fig=1;
OPEN cur;
REPEAT
FETCH cur INTO tidv;
INSERT INTO bbbb(tids) select min(pid) from `pws_posts` where `tid` = tidv;
UNTIL fig=1
END REPEAT;
CLOSE cur;
END$$
DELIMITER;
Call TEST1;
解释:临时建立了一个aaaa,表中存放`pws_posts`相同主题号(tid)中最小的回帖号(pid)
然后我们还得删除这些数据:
DELIMITER $$
DROP PROCEDURE IF EXISTS test2$$
CREATE PROCEDURE test2()
BEGIN
DECLARE pidv INT;
DECLARE fig INT;
DEClARE cur CURSOR FOR Select tids From `bbbb`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fig=1;
OPEN cur;
REPEAT
FETCH cur INTO pidv;
DELETE FROM `pws_posts` WHERE `pid` = pidv;
UNTIL fig=1
END REPEAT;
CLOSE cur;
END$$
DELIMITER ;
Call test2;
至此我的事情到底结束。
-----------------------
无废话版
1. 打开phpMyadmin,点SQL,输入代码,即可创建并运行存储过程
2. 给出一个最简单的游标使用,你就照着我这个粘贴进去,然后稍作修改即能为之己用:
DELIMITER
DROPPROCEDUREIFEXISTSTEST
CREATE PROCEDURE TEST()
BEGIN
DECLARE id INT;
DECLARE fig INT;
DEClARE cur CURSOR FOR Select 字段 From `表`;----> 此处支持所有合乎Select规则的查询以创建记录集
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fig=1;
OPEN cur; --------->打开游标
REPEAT ->>开始循环
FETCH cur INTO id; ---->若是首次进入,则相当于将第一行数据的第一个字段内容存入了变量id,假设你有多个字段,可用逗号隔开,比如id,name,age之类。
(此处可以填写所有合法的SQL语句,此处直接使用变量id,则相当于引用了表中的数据)
UNTIL fig=1 ---->数据行到尾了吗?如没有则继续下一行。
END REPEAT;
CLOSE cur;
END$$
DELIMITER ;
Call test2; --->调用刚才这个存储过程,切记哦,因为存储过程不会自动运行。