phpMyAdmin呼叫和生成MySQL的儲存過程以及CURSOR的應用
首先敘述一下我碰到的問題,如果這個講不清楚,則有可能壓根不知道這究竟有什麼用,有些事情總是在碰到困難需要解決非用不可的時候印象才會更深刻。
這是一個轉換工程,需要把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 $$
DROP PROCEDURE IF EXISTS TEST$$
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; --->呼叫剛才這個儲存過程,切記哦,因為儲存過程不會自動執行。