Như những người khác đã đề xuất, chúng tôi thường tránh lặp qua tập kết quả RBAR (hàng bằng cách tăng cường hàng) chủ yếu vì lý do hiệu suất. Chúng tôi chỉ không muốn có thói quen lặp lại một tập kết quả. Nhưng điều đó không trả lời câu hỏi bạn đã hỏi.
Để trả lời câu hỏi bạn đã hỏi, đây là một ví dụ đơn giản về chương trình lưu trữ MySQL sử dụng CURSOR để xử lý riêng các hàng được trả về bởi một truy vấn. MySQL không hỗ trợ các khối ẩn danh, vì vậy cách duy nhất để thực hiện việc này là trong một chương trình được lưu trữ trong MySQL, như QUY TRÌNH
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 ;
Để thực hiện thủ tục:
CALL loop_through_var_list();
LƯU Ý:Cú pháp để xử lý CURSOR trong MySQL hơi khác một chút so với các cơ sở dữ liệu khác.
Để có được "vòng lặp", chúng ta cần sử dụng LOOP ... END LOOP
xây dựng.
Nhưng để ngăn vòng lặp đó chạy mãi mãi, chúng ta cần câu lệnh LEAVE cho phép chúng ta thoát khỏi vòng lặp.
Chúng tôi sử dụng một bài kiểm tra có điều kiện để xác định thời điểm rời đi. Trong ví dụ này, chúng tôi muốn thoát ra sau khi xử lý xong hàng cuối cùng.
FETCH
sẽ đưa ra một ngoại lệ khi không còn hàng nào được tìm nạp.
Chúng tôi "bắt" ngoại lệ đó trong BỘ XỬ LÝ TIẾP TỤC (vì một số lý do phức tạp, các "bộ xử lý" phải khai báo những điều cuối cùng; MySQL sẽ phát sinh lỗi nếu chúng tôi cố gắng khai báo một cái gì đó sau một BỘ XỬ LÝ (không phải là một BỘ XỬ LÝ khác.)
Khi MySQL ném ngoại lệ "không còn hàng", điều đó sẽ kích hoạt mã trình xử lý. Trong ví dụ này, chúng tôi chỉ đặt một biến (có tên là done
) thành một giá trị.
Vì nó là một trình xử lý "continue", quá trình xử lý bắt đầu sao lưu tại câu lệnh nơi ngoại lệ được đưa ra, trong trường hợp này, đó sẽ là câu lệnh theo sau FETCH. Vì vậy, điều đầu tiên chúng tôi làm là kiểm tra xem chúng tôi đã "xong" hay chưa. Nếu chúng ta "xong", thì chúng ta thoát khỏi vòng lặp và đóng con trỏ.
Nếu không, chúng tôi biết rằng chúng tôi có một id
giá trị từ var_list
được lưu trữ trong một biến thủ tục có tên v_id
. Vì vậy, bây giờ chúng ta có thể làm bất cứ điều gì chúng ta muốn. Có vẻ như bạn muốn đặt một số văn bản SQL vào một biến do người dùng xác định (bao gồm giá trị của v_id vào văn bản SQL, sau đó CHUẨN BỊ, THỰC HIỆN và CHĂM SÓC TRƯỚC.
Đảm bảo khai báo v_id
biến có kiểu dữ liệu thích hợp, khớp với kiểu dữ liệu của id
trong var_list
, Tôi chỉ giả định rằng đó là INT.
Khi chúng tôi đến cuối vòng lặp, MySQL "lặp" lại phần đầu của vòng lặp và tắt chúng tôi lại tiếp tục.
Trong phần nội dung của vòng lặp, có thể bạn sẽ muốn CONCAT v_id vào văn bản SQL mà bạn muốn thực thi. Có vẻ như bạn đã xử lý xong phần chuẩn bị PREPARE, DEALLOCATE. Để thử nghiệm, bạn có thể muốn thêm mệnh đề LIMIT trên SELECT trong khai báo con trỏ, rồi thực hiện một lệnh SELECT v_id đơn giản; trong phần nội dung, chỉ để xác minh vòng lặp đang hoạt động, trước khi bạn thêm mã khác.
THEO DÕI
Tôi muốn đề cập đến một cách tiếp cận thay thế khác cho tác vụ, tức là chạy một loạt các câu lệnh dựa trên một mẫu, thay thế các giá trị được cung cấp từ một câu lệnh SQL select duy nhất ...
Ví dụ:nếu tôi có mẫu này:
SELECT *
INTO OUTFILE '/tmp/[email protected]'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM data
WHERE id = @ID
ORDER BY 1
và tôi cần thay thế các lần xuất hiện của @ID bằng một giá trị id cụ thể từ danh sách được trả về từ câu lệnh SELECT, ví dụ:
SELECT id
FROM var_list
WHERE id IS NOT NULL
GROUP BY id
Tôi có thể sẽ không sử dụng chương trình được lưu trữ MySQL với vòng lặp CURSOR, tôi sẽ sử dụng một cách tiếp cận khác.
Tôi sẽ sử dụng câu lệnh SELECT để tạo một tập hợp các câu lệnh SQL có thể được thực thi. Giả sử id
là kiểu số nguyên, tôi có thể sẽ làm như thế này:
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
Đối với mọi giá trị của id
trả về từ s
, câu lệnh trả về văn bản của câu lệnh SQL SELECT có thể (và cần) thực thi. Ghi lại nó vào một tệp văn bản sẽ cung cấp cho tôi một tập lệnh SQL mà tôi có thể chạy.