MySQL -> Lặp qua bảng, chạy một thủ tục được lưu trữ trên mỗi mục


8

Tôi có một cơ sở dữ liệu với 'sách' (truyện ngắn cho trẻ em) và sẽ rất hữu ích khi có số lượng từ của từng từ trong sách.

Tôi đã tìm ra cách lấy số từ cho mỗi từ bằng cách sử dụng:

SELECT SUM
( 
    ROUND
    ( 
        (LENGTH(pageText) - LENGTH (REPLACE (pageText, "Word", "")))
        /LENGTH("Word")
    )
) FROM pages WHERE bookID = id;

Mà làm việc tuyệt vời để đếm các từ. NHƯNG nó yêu cầu tôi đi qua từng cuốn sách và lấy ra từng từ và chạy nó qua chức năng đó (tôi đã lưu nó dưới dạng Thủ tục lưu trữ.)

Tôi có một bảng chứa mỗi từ, không có bản sao.

Câu hỏi của tôi: có cách nào để tôi có thể thực hiện một số loại vòng lặp "cho mỗi" trên bảng Words bằng cách sử dụng quy trình được lưu trữ của mình không?

I E. vượt qua thủ tục được lưu trữ một ID sách và một từ và ghi lại kết quả. Làm MỌI từ, cho MỌI cuốn sách. Do đó tiết kiệm cho tôi rất nhiều thời gian thủ công ... Đây có phải là điều tôi thậm chí nên làm từ phía DB không? Tôi có nên thử nó với PHP không?

Thành thật bất kỳ đầu vào được đánh giá rất cao!


1
Bạn có thể tạo một bảng gồm (tất cả) các từ bằng cách phân tích các cuốn sách. Sau đó, nó sẽ trở thành một lựa chọn tham gia sách để từ. Không có vòng lặp cần thiết ở đó.
jkavalik

Một số tác vụ được thực hiện tốt hơn trong ngôn ngữ lập trình thực, không phải SQL. Trong PHP nó có thể là một cái gì đó như count(explode(' ', $pageText))+1. Hoặc một cái gì đó phức tạp hơn để xử lý nhiều khoảng trống giữa các từ, có lẽ liên quanpreg_replace('/\s+/', ' ', $pageText)
Rick James

Đối với Perl, nó có thể ngắn như 1+split(/\s+/, $pageText). Số 1 là vì số đếm là khoảng trắng, không phải từ.
Rick James

Câu trả lời:


14

Tạo một thủ tục thứ hai sử dụng hai con trỏ lồng nhau.

Các con trỏ trong các thủ tục được lưu trữ cho phép bạn thực hiện một việc không giống SQL: lặp qua kết quả đặt một hàng tại một thời điểm, đặt các giá trị cột được chọn thành các biến và thực hiện mọi thứ với chúng.

Chúng dễ bị sử dụng sai, vì SQL, là khai báo thay vì thủ tục, thường không cần "cho mỗi hoạt động", nhưng trong trường hợp này, nó có vẻ như là một ứng dụng hợp lệ.

Khi bạn hiểu rõ về chúng, các con trỏ rất dễ, nhưng chúng đòi hỏi một cách tiếp cận có cấu trúc trong mã hỗ trợ không phải lúc nào cũng trực quan.

Gần đây tôi đã cung cấp một số mã "soạn sẵn" khá chuẩn để làm việc với một con trỏ để gọi một thủ tục được lưu trữ trong câu trả lời trên Stack Overflow , và tôi sẽ mượn rất nhiều từ câu trả lời đó, bên dưới.


Sử dụng một con trỏ đòi hỏi một số mã soạn sẵn tiêu chuẩn để bao quanh nó.

Bạn nhận SELECTcác giá trị bạn muốn vượt qua, từ bất cứ nơi nào bạn nhận được chúng (có thể là bảng tạm thời, bảng cơ sở hoặc dạng xem và có thể bao gồm các lệnh gọi đến các hàm được lưu trữ) và sau đó gọi thủ tục tồn tại của bạn với các giá trị đó.

Dưới đây là một ví dụ hợp lệ về cú pháp của mã cần thiết, với các bình luận để giải thích mỗi thành phần đang làm gì.

Ví dụ này sử dụng 2 cột để truyền 2 giá trị cho thủ tục được gọi.

Lưu ý rằng có những sự kiện xảy ra ở đây theo một thứ tự cụ thể vì một lý do. Các biến phải được khai báo trước, các con trỏ phải được khai báo trước khi xử lý tiếp tục của chúng và các vòng lặp phải tuân theo tất cả những điều đó.

Bạn không thể thực hiện những thứ không theo thứ tự, vì vậy khi bạn lồng một con trỏ vào bên trong một con trỏ khác, bạn phải đặt lại phạm vi thủ tục bằng cách lồng mã bổ sung bên trong BEGIN... ENDcác khối trong thân thủ tục; ví dụ: nếu bạn cần một con trỏ thứ hai bên trong vòng lặp, bạn chỉ cần khai báo nó bên trong vòng lặp, bên trong một khối BEGIN... khác END.

DELIMITER $$

DROP PROCEDURE IF EXISTS `my_proc` $$
CREATE PROCEDURE `my_proc`(arg1 INT) -- 1 input argument; you might need more or fewer
BEGIN

-- declare the program variables where we'll hold the values we're sending into the procedure;
-- declare as many of them as there are input arguments to the second procedure,
-- with appropriate data types.

DECLARE val1 INT DEFAULT NULL;
DECLARE val2 INT DEFAULT NULL;

-- we need a boolean variable to tell us when the cursor is out of data

DECLARE done TINYINT DEFAULT FALSE;

-- declare a cursor to select the desired columns from the desired source table1
-- the input argument (which you might or might not need) is used in this example for row selection

DECLARE cursor1 -- cursor1 is an arbitrary label, an identifier for the cursor
 CURSOR FOR
 SELECT t1.c1, 
        t1.c2
   FROM table1 t1
  WHERE c3 = arg1; 

-- this fancy spacing is of course not required; all of this could go on the same line.

-- a cursor that runs out of data throws an exception; we need to catch this.
-- when the NOT FOUND condition fires, "done" -- which defaults to FALSE -- will be set to true,
-- and since this is a CONTINUE handler, execution continues with the next statement.   

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

-- open the cursor

OPEN cursor1;

my_loop: -- loops have to have an arbitrary label; it's used to leave the loop
LOOP

  -- read the values from the next row that is available in the cursor

  FETCH NEXT FROM cursor1 INTO val1, val2;

  IF done THEN -- this will be true when we are out of rows to read, so we go to the statement after END LOOP.
    LEAVE my_loop; 
  ELSE -- val1 and val2 will be the next values from c1 and c2 in table t1, 
       -- so now we call the procedure with them for this "row"
    CALL the_other_procedure(val1,val2);
    -- maybe do more stuff here
  END IF;
END LOOP;

-- execution continues here when LEAVE my_loop is encountered;
-- you might have more things you want to do here

-- the cursor is implicitly closed when it goes out of scope, or can be explicitly closed if desired

CLOSE cursor1;

END $$

DELIMITER ;

Câu trả lời tuyệt vời, cực kỳ nhiều thông tin! Chưa nhận được nó, nhưng với các tài nguyên được cung cấp, tôi chắc chắn rằng tôi có thể khiến các con trỏ hoạt động! Cảm ơn bạn!
Michael MacDonald

điều này thật tuyệt sử dụng lặp lại / while khiến cho Proc của tôi bắn hai lần cho bản ghi cuối cùng, do đó yêu cầu kiểm tra bổ sung nhưng điều này giải quyết vấn đề đó.
Nick M

đóng con trỏ1; bị thiếu MỞ - ĐÓNG đang đi cùng nhau cho các con trỏ
Hoa hậu Felicia A Kovacs

2
Các con trỏ @MissFeliciaAKovacs chỉ có thể tồn tại trong phạm vi của một khối BEGIN/ ENDvà được đóng hoàn toàn khi chúng nằm ngoài phạm vi ... vì vậy việc đóng các con trỏ không thực sự cần thiết. Như một vấn đề thực tiễn, tôi cho rằng nó không cần thiết và không bao gồm nó, nhưng để hoàn thiện, tôi đã thêm CLOSEcâu vào câu trả lời.
Michael - sqlbot
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.