2010-06-25 25 views
16

Tôi có một chức năng được sử dụng như một kích hoạt INSERT. Hàm này xóa các hàng sẽ xung đột với [số sê-ri trong] hàng được chèn vào. Nó hoạt động rất đẹp, nên tôi thực sự không tranh luận về giá trị của khái niệm này.Biến có chứa số hàng bị ảnh hưởng bởi DELETE trước đó không? (trong một chức năng)

DECLARE 
re1 feeds_item.shareurl%TYPE; 
BEGIN 
SELECT regexp_replace(NEW.shareurl, '/[^/]+(-[0-9]+\.html)$','/[^/]+\\1') INTO re1; 
RAISE NOTICE 'DELETEing rows from feeds_item where shareurl ~ ''%''', re1; 

DELETE FROM feeds_item where shareurl ~ re1; 
RETURN NEW; 
END; 

Tôi muốn thêm vào NOTICE một chỉ báo về số lượng hàng bị ảnh hưởng (aka: deleted). Làm thế nào tôi có thể làm điều đó (bằng cách sử dụng LANGUAGE 'plpgsql')?

UPDATE: Căn cứ vào một số hướng dẫn tuyệt vời từ "Gà trong nhà bếp", tôi đã thay đổi nó như thế này:

DECLARE 
re1 feeds_item.shareurl%TYPE; 
num_rows int; 
BEGIN 
SELECT regexp_replace(NEW.shareurl, '/[^/]+(-[0-9]+\.html)$','/[^/]+\\1') INTO re1; 

DELETE FROM feeds_item where shareurl ~ re1; 
IF FOUND THEN 
    GET DIAGNOSTICS num_rows = ROW_COUNT; 
    RAISE NOTICE 'DELETEd % row(s) from feeds_item where shareurl ~ ''%''', num_rows, re1; 
END IF; 
RETURN NEW; 
END; 

Trả lời

9

Trong Oracle PL/SQL, biến hệ thống để lưu trữ các số xóa/chèn/hàng được cập nhật là:

SQL%ROWCOUNT 

Sau một tuyên bố DELETE/INSERT/UPDATE, và trước khi cam kết, bạn có thể lưu trữ SQL% ROWCOUNT trong một biến kiểu số. Hãy nhớ rằng COMMIT hoặc ROLLBACK được đặt lại thành ZERO giá trị của SQL% ROWCOUNT, vì vậy bạn phải sao chép giá trị SQL% ROWCOUNT trong một biến BEFORE COMMIT hoặc ROLLBACK.

Ví dụ:

BEGIN 
    DECLARE 
     affected_rows NUMBER DEFAULT 0; 
    BEGIN 
     DELETE FROM feeds_item 
      WHERE shareurl = re1; 

     affected_rows := SQL%ROWCOUNT; 
     DBMS_OUTPUT. 
     put_line (
      'This DELETE would affect ' 
     || affected_rows 
     || ' records in FEEDS_ITEM table.'); 
     ROLLBACK; 
    END; 
END; 

Tôi đã tìm thấy cũng SOLUTION thú vị này (nguồn: http://markmail.org/message/grqap2pncqd6w3sp)

On 4/7/07, Karthikeyan Sundaram đã viết:

Hi,

I am using 8.1.0 postgres and trying to write a plpgsql block. In that I am inserting a row. I want to check to see if the row has been 

được chèn hay không.

Trong oracle chúng ta có thể nói như thế này

begin 
    insert into table_a values (1); 
    if sql%rowcount > 0 
    then 
    dbms.output.put_line('rows inserted'); 
    else 
    dbms.output.put_line('rows not inserted'); 
end if; end; 

Có một cái gì đó tương đương với sql% rowcount trong postgres? Hãy giúp tôi.

Trân skarthi

Có thể:

http://www.postgresql.org/docs/8.2/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-ONEROW

Nhấp vào liên kết trên, bạn sẽ thấy nội dung này:

37.6.6. Lấy trạng thái kết quả Có một số cách để xác định hiệu ứng của một lệnh. Phương pháp đầu tiên là sử dụng lệnh GET DIAGNOSTICS, có dạng:

GET DIAGNOSTICS variable = item [, ...]; Lệnh này cho phép truy xuất chỉ báo trạng thái hệ thống. Mỗi mục là một từ khóa xác định giá trị trạng thái được gán cho biến được chỉ định (phải là loại dữ liệu phù hợp để nhận).Hiện tại, các mục trạng thái khả dụng là ROW_COUNT, số hàng được xử lý bởi lệnh SQL cuối cùng được gửi xuống công cụ SQL và RESULT_OID, OID của hàng cuối cùng được chèn bởi lệnh SQL gần đây nhất. Lưu ý rằng RESULT_OID chỉ hữu ích sau khi lệnh INSERT vào một bảng chứa OID.

Ví dụ:

NHẬN DIAGNOSTICS integer_var = ROW_COUNT; Phương pháp thứ hai để xác định tác động của lệnh là kiểm tra biến đặc biệt có tên FOUND, thuộc loại boolean. FOUND bắt đầu sai trong vòng mỗi lệnh gọi hàm PL/pgSQL. Nó được thiết lập theo từng loại sau đây: các câu lệnh:

Một câu lệnh INTO được đặt đúng nếu hàng được gán, false nếu không có hàng nào được trả về.

Một tuyên bố PERFORM đặt FOUND true nếu nó tạo (và loại bỏ) một hàng , sai nếu không có hàng nào được tạo.

báo cáo UPDATE, INSERT và DELETE được đặt thành ÂM THANH nếu ít nhất một hàng bị ảnh hưởng, sai nếu không có hàng nào bị ảnh hưởng.

Một câu lệnh FETCH FOUND true nếu nó trả về một hàng, false nếu không có hàng được trả về.

Câu lệnh FOR thiết lập đúng nếu nó lặp lại một hoặc nhiều lần, khác sai. Điều này áp dụng cho cả ba biến thể của câu lệnh FOR (số nguyên FOR vòng lặp, vòng lặp ghi cho vòng lặp FOR và bản ghi động FOR vòng lặp). FOUND được thiết lập theo cách này khi vòng lặp FOR thoát; bên trong việc thực thi vòng lặp , FOUND không được sửa đổi bởi câu lệnh FOR, mặc dù nó có thể thay đổi bằng cách thực hiện các câu lệnh khác trong phạm vi thân vòng lặp.

FOUND là biến cục bộ trong mỗi hàm PL/pgSQL; mọi thay đổi chỉ ảnh hưởng đến chức năng hiện tại.

+2

Vâng, ROW_COUNT là những gì bạn cần. –

+1

tuyệt vời, cảm ơn bạn! –

+2

Trích dẫn sách hướng dẫn không hữu ích. Liên kết là tốt. Nhưng tôi đến stackoverflow cho các ví dụ. – Neil

7

Đối với một giải pháp rất mạnh mẽ, đó là một phần của PostgreSQL SQL và không chỉ plpgsql bạn cũng có thể làm như sau:

with a as (DELETE FROM feeds_item WHERE shareurl ~ re1 returning 1) 
select count(*) from a; 

Bạn thực sự có thể nhận được nhiều hơn nữa các thông tin như:

with a as (delete from sales returning amount) 
select sum(amount) from a; 

để xem tổng số, theo cách này, bạn có thể nhận được bất kỳ tổng hợp và thậm chí nhóm và lọc nó.

+0

Tôi nghĩ rằng đó nên là 'shareurl ~ re1'. Bên cạnh đó, câu trả lời tuyệt vời! Tôi sẽ thêm cái này vào túi thủ thuật của tôi. –

+0

Nếu đây là một thủ tục được lưu trữ, loại biến nào là 'a'? –

+0

thật đáng buồn, cú pháp này không hoạt động trong Greenplum (Postgress 8.2) – ekkis

1

tôi sẽ chia sẻ mã của tôi (tôi đã có ý tưởng này từ Roelof Rossouw):

CREATE OR REPLACE FUNCTION my_schema.sp_delete_mytable(_id integer) 
    RETURNS integer AS 
$BODY$ 
    DECLARE 
    AFFECTEDROWS integer; 
    BEGIN 
    WITH a AS (DELETE FROM mytable WHERE id = _id RETURNING 1) 
    SELECT count(*) INTO AFFECTEDROWS FROM a; 
    IF AFFECTEDROWS = 1 THEN 
     RETURN 1; 
    ELSE 
     RETURN 0; 
    END IF; 
    EXCEPTION WHEN OTHERS THEN 
    RETURN 0; 
    END; 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
Các vấn đề liên quan