2010-02-18 31 views
8

Đây là con trỏ của tôi:Làm cách nào để tìm số bản ghi trong con trỏ Oracle PL/SQL?

CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE; 

tôi ngay lập tức mở con trỏ để khóa những hồ sơ này trong suốt thời gian thủ tục của tôi.

Tôi muốn tăng lỗi ứng dụng trong trường hợp có < 2 bản ghi trong con trỏ của tôi. Sử dụng thuộc tính C1% ROWCOUNT không thành công vì nó chỉ đếm số đã được tìm nạp từ trước đến nay.

Mẫu tốt nhất cho trường hợp sử dụng này là gì? Tôi có cần phải tạo biến MY_TABLE% ROWTYPE giả và sau đó lặp qua con trỏ để tìm nạp chúng và giữ một số hay có cách đơn giản hơn không? Nếu đây là cách để làm điều đó, sẽ lấy tất cả các hàng trong con trỏ của tôi ngầm đóng nó, do đó mở khóa những hàng đó, hoặc nó sẽ vẫn mở cho đến khi tôi đóng nó ngay cả khi tôi đã lấy tất cả chúng?

Tôi cần đảm bảo con trỏ vẫn mở cho nhiều tác vụ khác ngoài số này.

Trả lời

6

NB: tôi chỉ cần đọc lại bạn đặt câu hỏi .. và bạn muốn thất bại nếu chỉ có 1 kỷ lục .. tôi sẽ đăng một bản cập nhật mới trong một khoảnh khắc ..

cho phép bắt đầu ở đây ..

Từ Hướng dẫn và tham khảo 10g Release 2 (10.2) Part Number Cơ sở dữ liệu Oracle PL/SQL của người sử dụng B14261-01 reference

Tất cả hàng một bị khóa lại khi bạn mở con trỏ, không phải khi chúng được tìm nạp.Các hàng được mở khóa khi bạn cam kết hoặc quay trở lại giao dịch. Vì các hàng không còn bị khóa nữa nên bạn không thể tìm nạp từ con trỏ FOR UPDATE sau khi commit.

để bạn không cần phải lo lắng về việc mở khóa hồ sơ.

vì vậy hãy thử này ..

declare 
    CURSOR mytable_cur IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE; 

    TYPE mytable_tt IS TABLE OF mytable_cur %ROWTYPE 
    INDEX BY PLS_INTEGER; 

    l_my_table_recs mytable_tt; 
    l_totalcount NUMBER; 
begin 

    OPEN mytable_cur ; 
    l_totalcount := 0; 

    LOOP 
     FETCH mytable_cur 
     BULK COLLECT INTO l_my_table_recs LIMIT 100; 

     l_totalcount := l_totalcount + NVL(l_my_table_recs.COUNT,0); 

     --this is the check for only 1 row.. 
     EXIT WHEN l_totalcount < 2; 

     FOR indx IN 1 .. l_my_table_recs.COUNT 
     LOOP 
     --process each record.. via l_my_table_recs (indx) 

     END LOOP; 

     EXIT WHEN mytable_cur%NOTFOUND; 
    END LOOP; 

    CLOSE mytable_cur ; 
end; 

ALTERNATE ĐÁP tôi đọc bạn trả lời ngược trở lại để bắt đầu và nghĩ rằng bạn muốn thoát ra nếu có MORE sau đó 1 hàng .. không chính xác một. Vì vậy, đây là câu trả lời trước đây của tôi.

2 cách đơn giản để kiểm tra bản ghi CHỈ 1.

Lựa chọn 1 - Fetchs Explicit

declare 
    CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE; 
    l_my_table_rec C1%rowtype; 
    l_my_table_rec2 C1%rowtype; 
begin 

    open C1; 
    fetch c1 into l_my_table_rec; 

    if c1%NOTFOUND then 
     --no data found 
    end if; 

    fetch c1 into l_my_table_rec2; 
    if c1%FOUND THEN 
     --i have more then 1 row 
    end if; 
    close c1; 

    -- processing logic 

end; 

tôi hy vọng bạn sẽ có được ý tưởng.

Lựa chọn 2 - Exception Bắt

declare 
    CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE; 
    l_my_table_rec C1%rowtype; 
begin 
    begin 
    select * 
     from my_table 
     into l_my_table_rec 
    where salary < 50000 
     for update; 
    exception 
    when too_many_rows then 
     -- handle the exception where more than one row is returned 
    when no_data_found then 
     -- handle the exception where no rows are returned 
    when others then raise; 
    end; 

    -- processing logic 
end; 

Ngoài Hãy nhớ rằng: với một con trỏ rõ ràng .. bạn có thể% type biến của bạn không lưu nội dung con trỏ chứ không phải sau đó bảng gốc.

điều này đặc biệt hữu ích khi bạn tham gia vào truy vấn của mình.

Ngoài ra, rememebr bạn có thể cập nhật các hàng trong bảng với một kiểu tuyên bố

UPDATE table_name 
SET set_clause 
WHERE CURRENT OF cursor_name; 

, nhưng tôi sẽ chỉ làm việc nếu bạn chưa 'lấy' hàng 2nd ..


cho một số chi tiết thông tin về con trỏ cHO vòng .. thử Here

+0

Cảm ơn cho câu trả lời toàn diện. Tôi đã hy vọng có thể có một cách đơn giản hơn để có được một số lượng hồ sơ trong con trỏ mà không thực sự lấy tất cả dữ liệu đó, nhưng tôi thích giải pháp này hơn việc giới thiệu các điểm lưu trữ. Nó cảm thấy clunky để đọc một loạt các hồ sơ vào các biến mà tôi không có sử dụng cho (điều này thực sự chỉ là một khóa, và tôi cần phải biết có bao nhiêu hồ sơ tôi bị khóa). Trường hợp sử dụng của tôi là tôi cần xóa một bản ghi nhưng phải luôn có một bản ghi; sau khi tôi xác minh 2 tồn tại trong con trỏ của mình, tôi phát hành một lần xóa riêng biệt để xác định bản ghi cụ thể mà tôi muốn xóa. –

+0

okay .. có lẽ bạn nên thử ngược lại .. và chỉ cần một DELETE thẳng trên hàng 'trùng lặp' .. nếu họ không tồn tại .. sau đó không có gì xảy ra. nếu họ làm bạn còn lại với 1? .. tức là DELETE FROM my_table WHERE (chỉ chọn các hàng trùng lặp ở đây); – ShoeLace

0

Tạo điểm lưu trữ trước khi bạn lặp qua con trỏ và sau đó sử dụng một phần khôi phục khi bạn tìm thấy có < 2 bản ghi được trả lại.

0

Bạn có thể bắt đầu giao dịch và kiểm tra xem SELECT COUNT (*) MY_TABLE ĐÂU LƯƠNG < 50000 lớn hơn 1.

1

Nếu bạn đang tìm kiếm để thất bại whenver bạn có nhiều hơn 1 hàng trở lại, hãy thử này:

declare 
    l_my_table_rec my_table%rowtype; 
begin 
    begin 
    select * 
     from my_table 
     into l_my_table_rec 
    where salary < 50000 
     for update; 
    exception 
    when too_many_rows then 
     -- handle the exception where more than one row is returned 
    when no_data_found then 
     -- handle the exception where no rows are returned 
    when others then raise; 
    end; 

    -- processing logic 
end; 
1

Nếu đây là cách để làm điều đó, sẽ lấy tất cả các hàng trong con trỏ của tôi ngầm đóng nó, do đó mở khóa những hàng

Khóa sẽ có mặt trong suốt thời gian giao dịch (nghĩa là cho đến khi bạn thực hiện cam kết hoặc quay lại) bất kể khi nào (hoặc bạn có đóng con trỏ hay không).

tôi muốn đi cho

declare 
    CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;; 
    v_1 c1%rowtype; 
    v_cnt number; 
begin 
    open c_1; 
    select count(*) into v_cnt FROM MY_TABLE WHERE SALARY < 50000 and rownum < 3; 
    if v_cnt < 2 then 
    raise_application_error(-20001,'...'); 
    end if; 
    --other processing 
    close c_1; 
end; 

Có một cơ hội rất nhỏ, giữa thời gian con trỏ được mở (khóa hàng) và select count, ai đó chèn một hoặc nhiều hàng vào bảng với một mức lương dưới 50000. Trong trường hợp đó, lỗi ứng dụng sẽ được nâng lên nhưng con trỏ sẽ chỉ xử lý các hàng hiện tại khi con trỏ được mở. Nếu đó là một lo lắng, cuối cùng làm một kiểm tra trên hàng trăm% c_1 và, nếu vấn đề đó đã được kinh nghiệm, bạn sẽ cần phải quay trở lại một điểm lưu trữ.

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