2014-09-11 122 views
0

我有一張表,裏面填寫了ID號,我需要循環,並在準備好的語句中用作變量。我不知道是否需要爲此使用存儲過程,或者如果常規查詢可以執行此操作。這是一個簡單的例子。MySQL準備好的聲明 - 如何循環通過

SELECT id from var_list; 

loop through @ID = var_list.id .... 


SET @s1 = "SELECT * FROM data WHERE id = @ID"; 
PREPARE stmt1 FROM @s1; 
EXECUTE stmt1; 
DEALLOCATE PREPARE stmt1; 

正如評論所說,我只需要這個導出一些數據,我約50-100 ID在該表中並查詢寫入一次導出文件到服務器的單一。

編輯 我打算傾倒每次迭代的結果爲使用類似文件....

INTO OUTFILE '/tmp/orders.csv' 
FIELDS TERMINATED BY ',' 
ENCLOSED BY '"' 
LINES TERMINATED BY '\n' 
+2

你究竟想要完成什麼?一般來說,儘量遠離循環概念,因爲遊標速度非常慢。如果您要返回var_list表中的數據表結果,請改用「JOIN」。 – sgeddes 2014-09-11 04:11:46

+0

我需要導出一系列的CSV報告,我有爲每個ID編寫的查詢,但我有大約50個循環。 – Atari2600 2014-09-11 04:13:06

+0

我需要循環準備好的語句。 – Atari2600 2014-09-11 04:15:18

回答

1

正如其他人已經建議,我們通常避免主要出於性能原因循環結果集RBAR(行激動行)。我們只是不想養成循環結果集的習慣。但是這並不能回答你問的問題。

要回答你問的問題,這裏有一個MySQL存儲程序的基本例子,它使用CURSOR來單獨處理查詢返回的行。 MySQL不支持匿名塊,所以要做到這一點的唯一方法是在MySQL存儲程序,像一個過程

DELIMITER $$ 

CREATE PROCEDURE loop_through_var_list 
BEGIN 
    DECLARE done INT DEFAULT 0; 
    DECLARE v_id INT DEFAULT NULL; 
    DECLARE csr_var_list CURSOR FOR SELECT id FROM var_list ORDER BY id; 
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 
    OPEN csr_var_list; 
    get_id: LOOP 
     FETCH csr_var_list INTO v_id; 
     IF done = 1 THEN 
     LEAVE get_id; 
     END IF; 

     -- at this point, we have an id value in v_id, so we can do whatever 
     SET @s1 = CONCAT('SELECT ... WHERE id =''', v_id, ''' ...'); 


    END LOOP get_id; 
    CLOSE csr_var_list; 
END$$ 

DELIMITER ; 

要執行的過程:

CALL loop_through_var_list(); 

注:爲處理語法MySQL中的CURSOR與其他數據庫有很大不同。

要獲得「循環」,我們需要使用LOOP ... END LOOP結構。

但是爲了防止循環永久運行,我們需要一個LEAVE語句來允許我們退出循環。

我們使用條件測試來確定何時離開。在這個例子中,我們希望在處理完最後一行後退出。

FETCH將在沒有更多行被提取時拋出異常。我們在CONTINUE HANDLER中「捕捉」了異常(出於一些神祕的原因,「處理程序」必須聲明最後的東西;如果我們試圖在HANDLER之後聲明某些東西(如另一個HANDLER除外),則MySQL會拋出錯誤。 )

當MySQL拋出「沒有更多的行」異常,觸發該處理程序代碼。在這個例子中,我們只是一個變量(命名爲done)設定的值。

因爲它是一個「繼續「處理程序,處理在引發異常的語句處開始備份,在這種情況下,這將是FETCH後面的語句,因此,我們所做的第一件事是檢查我們是否」完成「。 '回覆「完成」,然後我們退出循環,並關閉光標。

否則,我們知道存儲在名爲v_id的過程變量中的id值爲var_list。所以現在我們可以做任何我們想要的。看起來您想將一些SQL文本放入用戶定義的變量中(包括v_id的值到SQL文本中,然後是PREPARE,EXECUTE和DEALLOCATE PREPARE)

請務必聲明v_id變量數據類型,它與var_list中的id列的數據類型匹配,我剛纔假設它是一個INT。

當我們到達循環結尾時,MySQL「循環」回到循環的開始處,並關閉我們再去

在循環的主體中,很可能你會想要將CONCAT v_id添加到你想要執行的SQL文本中,看起來你已經有了處理PREPARE,DEALLOCATE準備。對於測試,您可能希望在遊標聲明中的SELECT上添加一個LIMIT子句,然後執行一個簡單的SELECT v_id;在正文中,只是爲了驗證循環是否正常工作,然後添加更多代碼。


隨訪

我想提另一種替代的方法來工作,即運行一系列基於模板的語句,從單個SQL SELECT語句提供的值代...

舉例來說,如果我有這樣的模板:

SELECT * 
    INTO OUTFILE '/tmp/[email protected]' 
    FIELDS TERMINATED BY ',' ENCLOSED BY '"' 
    LINES TERMINATED BY '\n' 
FROM data 
WHERE id = @ID 
ORDER BY 1 

,我需要更換OCC從SELECT語句返回的列表中帶有特定id值的@ID的urrences,例如

SELECT id 
    FROM var_list 
WHERE id IS NOT NULL 
GROUP BY id 

我可能不會使用帶有CURSOR循環的MySQL存儲程序,我會使用不同的方法。

我會利用SELECT語句來生成一組可以執行的SQL語句。假設id是整數類型,我可能會做這樣的事情:

SELECT CONCAT(' SELECT * 
        INTO OUTFILE ''/tmp/orders_',s.id,'.csv'' 
        FIELDS TERMINATED BY '','' ENCLOSED BY ''"'' 
        LINES TERMINATED BY ''\n'' 
       FROM data 
       WHERE id = ',s.id,' 
       ORDER BY 1;') AS `stmt` 
FROM (SELECT v.id 
      FROM var_list v 
     WHERE v.id IS NOT NULL 
     GROUP BY v.id 
    ) s 
ORDER BY s.id 

對於來自s返回的id每一個值,該語句返回SQL SELECT語句可能(並且需要)執行的文本。將其捕獲到文本文件中會給我一個我可以運行的SQL腳本。

+0

非常感謝,你是一個豐富的知識! – Atari2600 2014-09-11 17:06:31

+1

@JasonB:我不確定我是否強調這一點:我提供的示例程序是未經測試的;這只是典型框架的演示。我強烈建議你測試一下,在過程體中沒有任何「真正的」工作(也許只需在循環體中添加一個'SELECT CONCAT('got v_id =',v_id)AS msg;'作爲一種方法得到一些輸出,看看光標循環工作。) – spencer7593 2014-09-11 22:37:48

+0

瞭解,它指着我在正確的方向,這就是我所需要的。 – Atari2600 2014-09-12 01:18:00

1

使用一個簡單的查詢,如:

SELECT * 
FROM data 
WHERE id IN (
    SELECT id 
    FROM var_list 
)