2013-07-24 12 views
43

Có một cách giải quyết choCó cách giải quyết nào cho ORA-01795: số lượng biểu thức tối đa trong danh sách là 1000 lỗi không?

'ORA-01795: maximum number of expressions in a list is 1000 error'

Tôi có một truy vấn và nó là lựa chọn lĩnh vực dựa trên giá trị của một lĩnh vực. Tôi đang sử dụng tại khoản và có giá trị 10000

dụ:

select field1, field2, field3 
from table1 
where name in 
(
'value1', 
'value2', 
... 
'value10000+' 
); 

Mỗi lần tôi thực hiện truy vấn tôi nhận được ORA-01795: maximum number of expressions in a list is 1000 error. Tôi đang cố gắng thực hiện truy vấn trong TOAD, không có sự khác biệt, cùng một lỗi. Làm cách nào để tôi sửa đổi truy vấn để làm cho nó hoạt động?

Cảm ơn trước

+1

đặt giá trị1 .... giá trị1000 + vào bảng và chọn tên trong (chọn giá trị từ bảng) – basdwarf

+2

Lỗi không phụ thuộc vào môi trường (ví dụ: SQL * Plus hoặc TOAD hoặc ...) nơi bạn thực hiện truy vấn của mình. –

Trả lời

73

Chỉ cần sử dụng nhiều trong các điều khoản để có được xung quanh này:

select field1, field2, field3 from table1 
where name in ('value1', 'value2', ..., 'value999') 
    or name in ('value1000', ..., 'value1999') 
    or ...; 
+0

Tại sao tôi không nghĩ về điều đó ?! Cảm ơn bạn. – Gideon

+2

Dường như đây là giải pháp và phải được đánh dấu là câu trả lời đúng. –

+0

Hãy nhớ rằng nếu bạn muốn sử dụng KHÔNG IN logic bạn cần VÀ những phát biểu này cùng nhau –

2

đó cũng là một cách để giải quyết vấn đề này. cho phép nói rằng bạn có hai bảng Table1 và Table2. và nó được yêu cầu để lấy tất cả các mục của Table1 không được giới thiệu/hiện diện trong Table2 bằng cách sử dụng truy vấn Criteria. Vì vậy, tiếp tục như thế này ...

List list=new ArrayList(); 
Criteria cr=session.createCriteria(Table1.class); 
cr.add(Restrictions.sqlRestriction("this_.id not in (select t2.t1_id from Table2 t2)")); 
. 
. 

. . . Nó sẽ thực hiện tất cả các hàm subquery trực tiếp trong SQL mà không bao gồm 1000 hoặc nhiều tham số trong SQL được chuyển đổi bởi khung công tác Hibernate. Nó làm việc cho tôi. Lưu ý: Bạn có thể cần phải thay đổi phần SQL theo yêu cầu của bạn.

7

Vui lòng sử dụng một truy vấn bên trong bên trong in -clause:

select col1, col2, col3... from table1 
where id in (select id from table2 where conditions...) 
+0

Có thể sử dụng tham gia bên trong, nó tăng đáng kể lựa chọn trong trường hợp của chúng tôi (8 giây so với 50 ms). – jahav

+1

Điều đó giả định dữ liệu của bạn cho mệnh đề where nằm trong một bảng khác trong cùng một DB, và bạn biết chọn để lấy nó! Không phải lúc nào cũng đúng – Adam

4

hơn Một cách:

CREATE OR REPLACE TYPE TYPE_TABLE_OF_VARCHAR2 AS TABLE OF VARCHAR(100); 
-- ... 
SELECT field1, field2, field3 
    FROM table1 
    WHERE name IN (
    SELECT * FROM table (SELECT CAST(? AS TYPE_TABLE_OF_VARCHAR2) FROM dual) 
); 

tôi không coi đó là tối ưu, nhưng nó hoạt động. Các gợi ý /*+ CARDINALITY(...) */ sẽ rất hữu ích bởi vì Oracle không hiểu cardinality của mảng được thông qua và không thể ước tính kế hoạch thực hiện tối ưu.

Là một thay thế khác - chèn hàng loạt vào bảng tạm thời và sử dụng truy vấn con cuối cùng cho thuộc tính IN.

15

Tôi chạy vào vấn đề này thời gian gần đây và đã tìm ra một cách táo bạo để làm việc đó mà không cần xâu chuỗi lại với nhau thêm tại các khoản

Bạn có thể tận dụng Tuples

SELECT field1, field2, field3 
FROM table1 
WHERE (1, name) IN ((1, value1), (1, value2), (1, value3),.....(1, value5000)); 

Oracle không cho phép> 1000 Tuples nhưng không giá trị đơn giản. Thông tin thêm về điều này ở đây,

https://community.oracle.com/message/3515498#3515498

https://community.oracle.com/thread/958612

Đây là tất nhiên nếu bạn không có tùy chọn sử dụng một subquery bên TRÊN để có được những giá trị mà bạn cần từ một bảng temp.

2

Tôi nhận ra đây là một câu hỏi cũ và đề cập đến TOAD nhưng nếu bạn cần mã hóa xung quanh bằng cách sử dụng C# bạn có thể chia danh sách thông qua vòng lặp for.Về cơ bản bạn có thể làm tương tự với Java bằng cách sử dụng subList();

List<Address> allAddresses = GetAllAddresses(); 
    List<Employee> employees = GetAllEmployees(); // count > 1000 

    List<Address> addresses = new List<Address>(); 

    for (int i = 0; i < employees.Count; i += 1000) 
    { 
     int count = ((employees.Count - i) < 1000) ? (employees.Count - i) - 1 : 1000; 
     var query = (from address in allAddresses 
        where employees.GetRange(i, count).Contains(address.EmployeeId) 
        && address.State == "UT" 
        select address).ToList(); 

     addresses.AddRange(query); 
    } 

Hy vọng điều này sẽ giúp ai đó.

13

Một số giải pháp workaround là:

1- Chia TRÊN khoản để nhiều tại các khoản nơi literals ít hơn 1000 và kết hợp chúng sử dụng HOẶC khoản:

Chia gốc "WHERE" khoản từ một "TRÊN "điều kiện để một số "IN" điều kiện:

Select id from x where id in (1, 2, ..., 1000,…,1500); 

để:

Select id from x where id in (1, 2, ..., 999) OR id in (1000,...,1500); 

2- Sử dụng Tuples: Giới hạn 1000 áp dụng cho các bộ mặt hàng đơn lẻ: (x) IN ((1), (2), (3), ...). Không có giới hạn nếu các bộ chứa hai hoặc nhiều mục: (x, 0) IN ((1,0), (2,0), (3,0), ...):

Select id from x where (x.id, 0) IN ((1, 0), (2, 0), (3, 0),.....(n, 0)); 

3 Sử dụng bảng tạm thời:

Select id from x where id in (select id from <temporary-table>); 
+0

Tóm tắt hay. Bạn có biết nếu có sự khác biệt về hiệu suất giữa các tùy chọn khác nhau không? – Adam

+0

Tôi có dữ liệu trong danh sách trong Java. Tôi đang tự hỏi về việc sử dụng mệnh đề with: 'with foo as (select: foo_1 id từ công đoàn kép tất cả ... chọn id foo_n từ kép) select * from bar inner join foo trên bar.id = foo.id' như là một thay thế để tạo các bảng tạm thời cho mỗi truy vấn. Có ý kiến ​​gì không? – Adam

1

operato đoàn

select * from tableA where tableA.Field1 in (1,2,...999) 
union 
select * from tableA where tableA.Field1 in (1000,1001,...1999) 
union 
select * from tableA where tableA.Field1 in (2000,2001,...2999) 
0

có một tùy chọn: with cú pháp. Để sử dụng ví dụ OP, hình thức này sẽ trông giống như:

with data as (
    select 'value1' name from dual 
    union all 
    select 'value2' name from dual 
    union all 
... 
    select 'value10000+' name from dual) 
select field1, field2, field3 
from table1 t1 
inner join data on t1.name = data.name; 

Tôi gặp sự cố này. Trong trường hợp của tôi, tôi đã có một danh sách dữ liệu trong Java, mỗi mục có một item_id và một customer_id. Tôi có hai bảng trong DB với các mục đăng ký cho các mục khách hàng tương ứng. Tôi muốn nhận danh sách tất cả đăng ký cho các mục hoặc cho khách hàng cho mục đó, cùng với id mục.

tôi đã cố gắng ba biến thể:

  1. Nhiều lựa chọn từ Java (sử dụng các bộ để có được xung quanh giới hạn)
  2. Với cú pháp
  3. tạm thời bảng

Lựa chọn 1: Nhiều Các lựa chọn từ Java

Về cơ bản, tôi f IRST

select item_id, token 
from item_subs 
where (item_id, 0) in ((:item_id_0, 0)...(:item_id_n, 0)) 

Sau đó

select cus_id, token 
from cus_subs 
where (cus_id, 0) in ((:cus_id_0, 0)...(:cus_id_n, 0)) 

Sau đó, tôi xây dựng một bản đồ trong Java với cus_id là chìa khóa và một danh sách các mục như giá trị, và đối với mỗi thuê bao khách hàng tìm thấy tôi thêm (vào danh sách quay trở lại từ lựa chọn đầu tiên) mục nhập cho tất cả các mục có liên quan với item_id đó.Đó là nhiều mã Messier

Lựa chọn 2: Với cú pháp

Nhận tất cả mọi thứ cùng một lúc với một SQL như

with data as (
    select :item_id_0 item_id, :cus_id_0 cus_id 
    union all 
    ... 
    select :item_id_n item_id, :cus_id_n cus_id) 
select I.item_id item_id, I.token token 
from item_subs I 
inner join data D on I.item_id = D.item_id 
union all 
select D.item_id item_id, C.token token 
from cus_subs C 
inner join data D on C.cus_id = D.cus_id 

Lựa chọn 3: Tạm bảng

Tạo một tạm thời toàn cầu bảng với ba trường: rownr (khóa chính), item_id và cus_id. Chèn tất cả các dữ liệu có sau đó chạy một lựa chọn rất giống với phương án 2, nhưng liên kết trong bảng tạm thời thay vì Performance with data

Đây là không một phân tích hiệu suất hoàn toàn khoa học.

  • Tôi đang chạy với cơ sở dữ liệu phát triển, với hơn 1000 hàng trong tập dữ liệu mà tôi muốn tìm đăng ký.
  • Tôi vừa thử một tập hợp dữ liệu.
  • Tôi không ở cùng vị trí thực tế với máy chủ DB của mình. Nó không xa lắm, nhưng tôi nhận thấy nếu tôi cố gắng từ nhà qua VPN thì tất cả sẽ chậm hơn nhiều, mặc dù nó là cùng một khoảng cách (và nó không phải là internet nhà của tôi đó là vấn đề).
  • Tôi đã thử nghiệm cuộc gọi đầy đủ, vì vậy API của tôi gọi một cuộc gọi khác (cũng chạy trong cùng một trường hợp trong dev) cũng kết nối với DB để lấy tập dữ liệu ban đầu. Nhưng đó là như nhau trong cả ba trường hợp.

YMMV.

Điều đó nói rằng, tùy chọn bảng tạm thời là nhiều hơn chậm hơn. Như trong gấp đôi rất chậm. Tôi đã nhận được 14-15 giây cho tùy chọn 1, 15-16 cho tùy chọn 2 và 30 cho tùy chọn 3.

Tôi sẽ thử lại từ cùng một mạng với máy chủ DB và kiểm tra xem điều đó có thay đổi mọi thứ khi tôi nhận được cơ hội.

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