2008-10-28 35 views
11

Làm cách nào để tạo một thủ tục lưu sẵn Oracle chấp nhận một số giá trị tham số được sử dụng để nạp một mệnh đề IN?Thủ tục lưu sẵn Oracle với các tham số cho mệnh đề IN

Đây là những gì tôi đang cố gắng đạt được. Tôi không biết cách khai báo trong PLSQL để chuyển một danh sách các khóa chính của các hàng mà tôi muốn cập nhật.

FUNCTION EXECUTE_UPDATE 
    (<parameter_list> 
    value IN int) 
    RETURN int IS 
BEGIN 
    [...other statements...] 
    update table1 set col1 = col1 - value where id in (<parameter_list>) 

    RETURN SQL%ROWCOUNT ; 
END; 

Ngoài ra, tôi muốn gọi thủ tục này từ C#, vì vậy nó phải tương thích với khả năng .NET.

Cảm ơn, Robert

Trả lời

25

Sử dụng CSV có lẽ là cách đơn giản nhất, giả sử bạn có thể chắc chắn 100% rằng các yếu tố của bạn sẽ không tự chứa chuỗi.

Cách thay thế và có lẽ mạnh mẽ hơn, cách thực hiện việc này là tạo loại tùy chỉnh dưới dạng bảng chuỗi. Giả sử chuỗi của bạn không bao giờ dài hơn 100 ký tự, sau đó bạn có thể có:

CREATE TYPE string_table AS TABLE OF varchar2(100); 

Sau đó bạn có thể vượt qua một biến kiểu này thành thủ tục lưu trữ của bạn và tham khảo trực tiếp. Trong trường hợp của bạn, một cái gì đó như thế này:

FUNCTION EXECUTE_UPDATE(
    identifierList string_table, 
    value int) 
RETURN int 
IS 
BEGIN 

    [...other stuff...] 

    update table1 set col1 = col1 - value 
    where id in (select column_value from table(identifierList)); 

    RETURN SQL%ROWCOUNT; 

END 

Chức năng table() biến kiểu tùy chỉnh của bạn vào một bảng với một cột duy nhất "COLUMN_VALUE", sau đó bạn có thể coi như bất kỳ bảng khác (để làm tham gia hoặc trong này case, subselects).

Vẻ đẹp của việc này là Oracle sẽ tạo ra một constructor cho bạn, vì vậy khi gọi thủ tục lưu trữ của bạn, bạn chỉ đơn giản là có thể viết:

execute_update(string_table('foo','bar','baz'), 32); 

Tôi giả định rằng bạn có thể xử lý việc xây dựng lệnh này programatically từ C#.

Là một sang một bên, tại công ty của tôi, chúng tôi có một số loại tùy chỉnh được định nghĩa là tiêu chuẩn cho danh sách các chuỗi, tăng gấp đôi, int và v.v. Chúng tôi cũng sử dụng Oracle JPublisher để có thể ánh xạ trực tiếp từ các loại này vào các đối tượng Java tương ứng. Tôi đã có một cái nhìn nhanh chóng xung quanh nhưng tôi không thể nhìn thấy bất kỳ tương đương trực tiếp cho C#. Chỉ cần nghĩ rằng tôi muốn đề cập đến nó trong trường hợp các nhà phát triển Java gặp phải câu hỏi này.

+2

Ghi chú nhanh - CSV sẽ không hoạt động bởi chính nó, vì Oracle sẽ coi nó là một chuỗi. – sarsnake

+0

Không nên là '... từ string_table (identifierList)); ... '? –

-1

Tôi đã không thực hiện nó cho Oracle, nhưng với SQL Server, bạn có thể sử dụng một chức năng để chuyển đổi một chuỗi CSV vào một bảng, sau đó có thể được sử dụng trong một khoản IN. Nó phải là thẳng về phía trước để lại viết những dòng này cho Oracle (tôi nghĩ!)

CREATE Function dbo.CsvToInt (@Array varchar(1000)) 
returns @IntTable table 
    (IntValue nvarchar(100)) 
AS 
begin 

    declare @separator char(1) 
    set @separator = ',' 

    declare @separator_position int 
    declare @array_value varchar(1000) 

    set @array = @array + ',' 

    while patindex('%,%' , @array) <> 0 
    begin 

     select @separator_position = patindex('%,%' , @array) 
     select @array_value = left(@array, @separator_position - 1) 

     Insert @IntTable 
     Values (Cast(@array_value as nvarchar)) 

     select @array = stuff(@array, 1, @separator_position, '') 
    end 

    return 
end 

Sau đó, bạn có thể vượt qua trong một chuỗi CSV (ví dụ như '0001,0002,0003') và làm điều gì đó như

UPDATE table1 SET 
     col1 = col1 - value 
WHERE id in (SELECT * FROM csvToInt(@myParam)) 
+0

Something tương tự có thể được thực hiện với PL/SQL nhưng nhanh hơn để chuyển một bộ sưu tập đến thủ tục dưới dạng chuỗi csv. Chuỗi csv cần phải được mã hóa đầu tiên trong PL/SQL. – tuinstoel

-1

Tại sao phải là thủ tục được lưu trữ? Bạn có thể xây dựng một tuyên bố chuẩn bị theo chương trình.

+1

tôi cần phải thực hiện trong thủ tục plsql báo cáo nhiều hơn là một "cập nhật". Tôi đơn giản hóa một chút vấn đề vì lợi ích của ví dụ. –

0

Có một bài viết trên trang web AskTom hiển thị cách tạo hàm để phân tích chuỗi CSV và sử dụng hàm này trong câu lệnh của bạn theo cách tương tự với ví dụ về SQL Server đã cho.

Xem Asktom

1

Tôi nghĩ rằng không có cách nào trực tiếp để tạo ra các thủ tục với số biến của tham số. Tuy nhiên có một số giải pháp một phần cho vấn đề, được mô tả here.

  1. Nếu có một số quá trình gọi quá trình loại cuộc gọi điển hình có thể hữu ích.
  2. Nếu có giới hạn trên về số tham số (và loại của chúng cũng được biết trước), giá trị mặc định của thông số có thể hữu ích.
  3. Tùy chọn tốt nhất có thể là việc sử dụng các biến con trỏ là con trỏ đến con trỏ cơ sở dữ liệu.

Rất tiếc, tôi không có kinh nghiệm về môi trường .NET.

+0

"không có cách trực tiếp nào để tạo các thủ tục với số lượng tham số khác nhau" ... Có, sử dụng TẠO LOẠI NHƯ xxx TABLE của yyy và sau đó sử dụng kiểu đó làm kiểu tham số. – ObiWanKenobi

+0

Không, nó không phải là một giải pháp trực tiếp. Dù sao phương pháp của bạn là câu trả lời được chấp nhận có từ năm 2008. – rics

0

Tại sao không chỉ sử dụng danh sách tham số dài và tải các giá trị vào một hàm tạo bảng? Đây là SQL/PSM cho thủ thuật này

UPDATE Foobar 
    SET x = 42 
WHERE Foobar.keycol 
     IN (SELECT X.parm 
      FROM (VALUES (in_p01), (in_p02), .., (in_p99)) X(parm) 
      WHERE X.parm IS NOT NULL); 
2

Tôi tìm thấy bài viết sau đây của Mark A. Williams mà tôi nghĩ là một bổ sung hữu ích cho chủ đề này. Bài báo đưa ra một ví dụ tốt về đi qua mảng từ C# để procs PL/SQL sử dụng các mảng kết hợp (LOẠI myType LÀ MỤC mytable.row% TYPE INDEX THEO PLS_INTEGER):

Great article by Mark A. Williams

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