2009-10-26 43 views
7

Có ứng dụng C# .net mà tôi cần sửa đổi. Các truy vấn vào lúc này một cách hiệu quả thực hiện điều này:Tham số Oracle với câu lệnh IN?

select * from contract where contractnum = :ContractNum 

(rất đơn giản, chỉ cần để hiển thị chúng tôi đang sử dụng = và một tham số)

Đó tham số được đọc từ file Settings.settings trên Ứng dụng C# và có một chuỗi trong đó. Tôi cần phải sửa đổi nó để bao gồm nhiều hợp đồng, vì vậy tôi hình tôi có thể thay đổi SQL thành:

select * from contract where contractnum in (:ContractNum) 

nhưng không trả về kết quả, bất kể tôi định dạng chuỗi trong tham số như thế nào.

Có cách nào tôi có thể nhận được oracle để thực hiện IN với tham số không?

bất kỳ trợ giúp nào được đánh giá cao, cảm ơn tất cả.

+0

Khi bạn sử dụng odp.net hoặc devart làm nhà cung cấp dữ liệu, bạn có thể sử dụng bộ sưu tập Oracle (một bảng lồng nhau) làm tham số. Đây là cách nhanh nhất nhưng không thể thực hiện được khi bạn sử dụng system.data.oracleclient. Vậy bạn sử dụng loại dataprovider nào? – tuinstoel

Trả lời

2

Chưa tìm thấy db hỗ trợ đánh giá biến chuỗi đơn chứa dấu phẩy để tách biệt thành mệnh đề IN duy nhất.

Tùy chọn của bạn là chuỗi con biến để các nội dung biến phân cách bằng dấu phẩy được chuyển thành hàng, vì vậy bạn có thể tham gia vào điều này. Hoặc sử dụng SQL động, là một câu lệnh SQL được xây dựng như một chuỗi trong một sproc trước khi câu lệnh được thi hành.

+0

Tôi tìm thấy một tài liệu tham khảo để sử dụng & thay vì: để xác định tham số và hoạt động: giá trị Parameter: '1.182.411', '1.182.423' SQL: select * from hợp đồng mà contractnum trong (& ContractNum) Tôi không có ý tưởng tại sao công trình này hoạt động, hoặc liệu nó có được "chính thức" hỗ trợ bởi Orace hay chỉ TOAD. Bạn đã từng sử dụng Oracle chưa? Bất kỳ ý tưởng sự khác biệt là gì? – Gareth

+0

: biến là biến liên kết; thời gian duy nhất tôi nhớ lại bằng cách sử dụng & biến là để xác định/sử dụng một biến ràng buộc trong PLSQL Developer. –

+2

Dấu và là ký tự mặc định cho biết biến thay thế trong SQL * Plus. TOAD (và các IDE khác) hỗ trợ một số cú pháp SQL * Plus. – APC

6

bạn có thể sử dụng hàm pipelined để chuyển đổi chuỗi thành bảng có thể được sử dụng với toán tử IN. Ví dụ (thử nghiệm với 10gR2):

SQL> select * from table(demo_pkg.string_to_tab('i,j,k')); 

COLUMN_VALUE 
----------------- 
i 
j 
k 

với các gói sau:

SQL> CREATE OR REPLACE PACKAGE demo_pkg IS 
    2  TYPE varchar_tab IS TABLE OF VARCHAR2(4000); 
    3  FUNCTION string_to_tab(p_string VARCHAR2, 
    4       p_delimiter VARCHAR2 DEFAULT ',') 
    5  RETURN varchar_tab PIPELINED; 
    6 END demo_pkg; 
    7/

Package created 
SQL> CREATE OR REPLACE PACKAGE BODY demo_pkg IS 
    2  FUNCTION string_to_tab(p_string VARCHAR2, 
    3       p_delimiter VARCHAR2 DEFAULT ',') 
    4  RETURN varchar_tab PIPELINED IS 
    5  l_string   VARCHAR2(4000) := p_string; 
    6  l_first_delimiter NUMBER := instr(p_string, p_delimiter); 
    7  BEGIN 
    8  LOOP 
    9   IF nvl(l_first_delimiter,0) = 0 THEN 
10    PIPE ROW(l_string); 
11    RETURN; 
12   END IF; 
13   PIPE ROW(substr(l_string, 1, l_first_delimiter - 1)); 
14   l_string   := substr(l_string, l_first_delimiter + 1); 
15   l_first_delimiter := instr(l_string, p_delimiter); 
16  END LOOP; 
17  END; 
18 END demo_pkg; 
19/

Package body created 

truy vấn của bạn sẽ trông như thế này:

select * 
    from contract 
where contractnum in (select column_value 
         from table(demo_pkg.string_to_tab(:ContractNum))) 
+1

+1 - AFAIK, đây là cách duy nhất để sử dụng tất cả: biến liên kết, số lượng phần tử không xác định và mệnh đề "IN". Nếu bạn có giới hạn trên về số lượng phần tử, bạn luôn có thể mã câu lệnh để sử dụng số phần tử đó và thay thế null khi có phần giữ chỗ còn sót lại – dpbradley

+0

Không có cách nào để sử dụng các biến liên kết. Bạn cũng có thể liên kết một bộ sưu tập các số của Oracle và tham gia với bảng (: số). Bạn sẽ không cần hàm pipelined nữa. Tuy nhiên, nhà cung cấp dữ liệu của bạn phải hỗ trợ nó. – tuinstoel

+0

Đây là phương pháp mà chúng tôi đã sử dụng trong gần 10 năm. Sau khi (cuối cùng) chuyển sang sử dụng ODP.NET, chúng tôi buộc phải sử dụng phương thức được đánh dấu trong câu trả lời được đăng bởi tuinstoel. Điều đó có vẻ là một giải pháp đẹp hơn nhiều, thay vì tách chuỗi. – Carl

6

Bạn có thể sử dụng một bộ sưu tập Oracle số như một tham số (biến liên kết) khi bạn sử dụng ODP.NET làm dataprovider. Điều này làm việc với máy chủ Oracle 9, 10 hoặc 11 và phát hành ODP.net> = 11.1.0.6.20.

Một giải pháp tương tự có thể xảy ra khi bạn sử dụng bộ dữ liệu .NET của Devart cho Oracle.

Hãy chọn hợp đồng với contractnum của 3 và 4.

Chúng ta phải sử dụng một loại Oracle để chuyển một mảng các số hợp đồng để truy vấn của chúng tôi.

MDSYS.SDO_ELEM_INFO_ARRAY được sử dụng vì nếu chúng ta sử dụng kiểu Oracle đã định sẵn này, chúng ta không phải định nghĩa kiểu Oracle của chúng ta. Bạn có thể điền MDSYS.SDO_ELEM_INFO_ARRAY với số lượng tối đa 1048576.

using Oracle.DataAccess.Client; 
using Oracle.DataAccess.Types; 

[OracleCustomTypeMappingAttribute("MDSYS.SDO_ELEM_INFO_ARRAY")] 
public class NumberArrayFactory : IOracleArrayTypeFactory 
{ 
    public Array CreateArray(int numElems) 
    { 
    return new Decimal[numElems]; 
    } 

    public Array CreateStatusArray(int numElems) 
    { 
    return null; 
    } 
} 

private void Test() 
{ 
    OracleConnectionStringBuilder b = new OracleConnectionStringBuilder(); 
    b.UserID = "sna"; 
    b.Password = "sna"; 
    b.DataSource = "ora11"; 
    using (OracleConnection conn = new OracleConnection(b.ToString())) 
    { 
    conn.Open(); 
    using (OracleCommand comm = conn.CreateCommand()) 
    { 
     comm.CommandText = 
     @" select /*+ cardinality(tab 10) */ c.* " + 
     @" from contract c, table(:1) tab " + 
     @" where c.contractnum = tab.column_value"; 

     OracleParameter p = new OracleParameter(); 
     p.OracleDbType = OracleDbType.Array; 
     p.Direction = ParameterDirection.Input; 
     p.UdtTypeName = "MDSYS.SDO_ELEM_INFO_ARRAY"; 
     //select contract 3 and 4 
     p.Value = new Decimal[] { 3, 4 }; 
     comm.Parameters.Add(p); 

     int numContracts = 0; 
     using (OracleDataReader reader = comm.ExecuteReader()) 
     { 
     while (reader.Read()) 
     { 
      numContracts++; 
     } 
     } 
     conn.Close(); 
    } 
    } 
} 

Chỉ mục trên contract.contractnum không được sử dụng khi bỏ qua gợi ý/* + cardinality (tab 10) * /. Tôi cho rằng contractnum là khóa chính nên cột này sẽ được lập chỉ mục.

Xem thêm ở đây: http://forums.oracle.com/forums/thread.jspa?messageID=3869879#3869879

+0

Đọc thêm: http://blog.tanelpoder.com/2012/08/02/the-limitations-of-cursor_sharing-force-and-force_matching_signature-for-sql-plan-stability/ – TTT

+0

Điều này phù hợp với kịch bản của chúng tôi. Gotcha cho tôi đã bao gồm NumberArrayFactory, mặc dù nó không được sử dụng một cách rõ ràng trong mã. – Carl

0

Để sử dụng tham số với tuyên bố TRÊN bạn có thể sử dụng xây dựng này:

select * from contract where contractnum 
in (select column_value from table (:ContractNum)) 

nơi ContractNum là kiểu mảng tùy chỉnh.

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