2009-05-22 42 views
7

Tôi có aa vòng lặp con trỏ đó là xây dựng một chuỗi bằng cách ghép các nội dung của một bảng với nhau, sử dụng mã cùng những dòng này:Oracle con trỏ chạy qua mục cuối cùng hai lần

OPEN cur_t; 
LOOP 
    FETCH cur_t INTO v_texttoadd; 

    v_string := v_string || v_texttoadd; 
EXIT WHEN cur_t%notfound; 
END LOOP; 

Vấn đề là, tất nhiên, điều đó mục cuối cùng được thêm hai lần vì hệ thống chạy qua nó một lần nữa trước khi nhận ra rằng không có gì để tìm.

tôi đã cố gắng chơi xung quanh với một cái gì đó giống như

OPEN cur_t; 
WHILE cur_t%found; 
LOOP 
    FETCH cur_t INTO v_texttoadd; 

    v_string := v_string || v_texttoadd; 
END LOOP; 

Nhưng điều đó dường như không quay trở lại bất cứ điều gì cả.

Tôi nên sử dụng loại cú pháp nào để mỗi hàng chỉ xuất hiện trong chuỗi kết quả một lần?

Trả lời

21

Bạn có thể thử này:

OPEN cur_t; 
LOOP 
    FETCH cur_t INTO v_texttoadd; 
    EXIT WHEN cur_t%notfound; 
    v_string := v_string || v_texttoadd; 
END LOOP; 

này hoạt động vì% notfound được thiết lập khi FETCH được thực hiện và không có nhiều hàng bất kỳ để lấy. Trong ví dụ của bạn, bạn đã kiểm tra% notfound sau khi kết nối và kết quả là bạn đã có bản sao cuối cùng.

+0

Đã không làm việc cho tôi. Hãy xem câu trả lời của tôi nếu bạn quan tâm. –

0

câu trả lời đơn giản, mặc dù có thể không phải là tốt nhất:

OPEN cur_t; 
LOOP 
    FETCH cur_t INTO v_texttoadd; 
    IF cur_t%found THEN 
     v_string := v_string || v_texttoadd; 
    END IF; 
EXIT WHEN cur_t%notfound; 
END LOOP; 
+0

Tôi nghĩ, dựa trên sự thụt lề của bạn, bạn giả sử rằng câu lệnh EXIT là một phần của cú pháp LOOP và phải đến cuối vòng lặp. Điều này không đúng; EXIT chỉ là một câu lệnh giống như bất kỳ câu lệnh nào khác trong phần thân của vòng lặp. Đây là lý do tại sao, như những người khác đã cho thấy, bạn có thể đặt nó ngay lập tức sau khi FETCH để giải quyết vấn đề của bạn. –

+0

Đã không làm việc cho tôi. Hãy xem câu trả lời của tôi nếu bạn quan tâm. –

2

% notfound được thiết lập khi lấy thất bại trong việc lấy một hàng mới.

một cách khác có thể (cái này tránh "nếu" s và "thoát khi" s):

OPEN cur_t; 
FETCH cur_t INTO v_texttoadd; 
WHILE cur_t%found LOOP 
    v_string := v_string || v_texttoadd; 
    FETCH cur_t INTO v_texttoadd; 
END LOOP; 
+0

Tôi e rằng đây là câu trả lời đúng * duy nhất * ở đây! –

3

câu trả lời phải đã được đưa ra, nhưng chỉ xây dựng một chút.

Mô phỏng tình hình hiện tại của bạn:

SQL> declare 
    2 cursor cur_t 
    3 is 
    4 select ename 
    5  from emp 
    6  where deptno = 10 
    7 ; 
    8 v_texttoadd emp.ename%type; 
    9 v_string varchar2(100); 
10 begin 
11 open cur_t; 
12 loop 
13  fetch cur_t into v_texttoadd; 
14  v_string := v_string || v_texttoadd; 
15  exit when cur_t%notfound; 
16 end loop 
17 ; 
18 dbms_output.put_line(v_string); 
19 end; 
20/
CLARKKINGMILLERMILLER 

PL/SQL-procedure is geslaagd. 

Đây MILLER được in hai lần. Bởi chỉ cần chuyển đổi báo cáo kết quả EXIT và sự phân công v_string, bạn sẽ có được kết quả mong muốn:

SQL> declare 
    2 cursor cur_t 
    3 is 
    4 select ename 
    5  from emp 
    6  where deptno = 10 
    7 ; 
    8 v_texttoadd emp.ename%type; 
    9 v_string varchar2(100); 
10 begin 
11 open cur_t; 
12 loop 
13  fetch cur_t into v_texttoadd; 
14  exit when cur_t%notfound; 
15  v_string := v_string || v_texttoadd; 
16 end loop 
17 ; 
18 dbms_output.put_line(v_string); 
19 end; 
20/
CLARKKINGMILLER 

PL/SQL-procedure is geslaagd. 

Tuy nhiên,/code PL SQL của bạn trở nên dễ dàng hơn khi sử dụng một con trỏ-cho-loop. Sau đó, bạn có thể bỏ qua biến v_texttoadd và số dòng trong vòng lặp của bạn giảm:

SQL> declare 
    2 cursor cur_t 
    3 is 
    4 select ename 
    5  from emp 
    6  where deptno = 10 
    7 ; 
    8 v_string varchar2(100); 
    9 begin 
10 for r in cur_t 
11 loop 
12  v_string := v_string || r.ename; 
13 end loop 
14 ; 
15 dbms_output.put_line(v_string); 
16 end; 
17/
CLARKKINGMILLER 

PL/SQL-procedure is geslaagd. 

Bạn cũng có thể sử dụng SQL thẳng để hoàn thành công việc. Ví dụ với mệnh đề mô hình SQL, nếu bạn đang sử dụng phiên bản 10g hoặc cao hơn:

SQL> select string 
    2 from (select string 
    3    , rn 
    4    from emp 
    5   where deptno = 10 
    6   model 
    7     dimension by (rownum rn) 
    8     measures (ename, cast(null as varchar2(100)) string) 
    9     (string[any] order by rn desc = ename[cv()] || string[cv()+1] 
10     ) 
11  ) 
12 where rn = 1 
13/

STRING 
----------------------------------------------------------------------------------- 
CLARKKINGMILLER 

1 rij is geselecteerd. 

Kính trọng, Rob.

+0

+1 cho FOR .. IN ... LOOP gợi ý và ví dụ. Con trỏ CHO vòng là bạn bè của bạn ;-) Thêm tiền thưởng: bạn thường có thể nhúng câu lệnh chọn con trỏ của bạn trong vòng lặp FOR: FOR Rec IN (SELECT ...) LOOP – DCookie

0

Tôi đã thực hiện nhiều giải pháp dựa trên con trỏ trong Microsoft SQL, luôn hoạt động hoàn hảo (Ngày cũ tốt! Tôi muốn SQL Server của mình trở lại rất nhiều!) Tuy nhiên tất cả các câu trả lời cho câu hỏi này đã chứng minh là sai với tôi, hàng cuối cùng của con trỏ là ALWAYS được thực thi hai lần, cho dù tôi có tuân theo phương pháp được chúng đề xuất đến mức nào.

Hãy quên đi một thời gian không loop và quên exit, đây là những gì bạn PHẢI làm để tránh thực hiện kép (khá nhiều việc bạn làm trong T-SQL!).

cursor c_mm is select a, b, c, d from mytable; 

    begin 
    open c_mm; 
    fetch c_mm into a, b, c, d; 
    while (not c_mm%notfound) loop 
     -- do what you have to do here 

     fetch c_mm into a, b, c, d; 
    end loop; 
    close c_mm; 
    end; 

Mà tôi thực sự không hiểu là tại sao tất cả bài viết Oracle kiến ​​thức cơ bản và các bài viết diễn đàn (và stackoverflow) thúc đẩy này giải pháp thoát-trong-một-loop mà rõ ràng là sai!

Các vấn đề liên quan