ORA-01795에 대한 해결 방법이 있습니까? 목록의 최대 표현식 수는 1000 오류입니까?
에 대한 해결 방법이 있습니까?
'ORA-01795: maximum number of expressions in a list is 1000 error'
쿼리가 있는데 한 필드의 값을 기반으로 필드를 선택하고 있습니다. in 절을 사용하고 있으며 10000 개 이상의 값이 있습니다.
예:
select field1, field2, field3
from table1
where name in
(
'value1',
'value2',
...
'value10000+'
);
쿼리를 실행할 때마다 ORA-01795: maximum number of expressions in a list is 1000 error
. 나는 TOAD에서 쿼리를 실행하려고하는데 차이가 없으며 동일한 오류가 발생합니다. 작동하도록 쿼리를 수정하려면 어떻게해야합니까?
미리 감사드립니다
이 문제를 해결하려면 여러 절을 사용하십시오.
select field1, field2, field3 from table1
where name in ('value1', 'value2', ..., 'value999')
or name in ('value1000', ..., 'value1999')
or ...;
나는 최근 에이 문제를 만났고 추가 IN 절을 함께 묶지 않고 건방진 방법을 찾았습니다.
튜플을 사용할 수 있습니다.
SELECT field1, field2, field3
FROM table1
WHERE (1, name) IN ((1, value1), (1, value2), (1, value3),.....(1, value5000));
Oracle은> 1000 튜플을 허용하지만 단순한 값은 허용하지 않습니다. 여기에서 더 자세히,
https://community.oracle.com/message/3515498#3515498
및
https://community.oracle.com/thread/958612
물론 임시 테이블에서 필요한 값을 가져 오기 위해 IN 내부에서 하위 쿼리를 사용하는 옵션이없는 경우입니다.
몇 가지 해결 방법은 다음과 같습니다.
1- IN 절을 리터럴이 1000 미만인 여러 IN 절로 분할하고 OR 절을 사용하여 결합합니다.
원래 "WHERE"절을 하나의 "IN"조건에서 여러 "IN"조건으로 분할합니다.
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- 튜플 사용 : 1000 개의 제한은 단일 항목 집합에 적용됩니다 : (x) IN ((1), (2), (3), ...). 세트에 두 개 이상의 항목이 포함 된 경우 제한이 없습니다 : (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- 임시 테이블 사용 :
Select id from x where id in (select id from <temporary-table>);
한 가지 더 방법 :
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)
);
나는 그것이 최적이라고 생각하지 않지만 작동합니다. /*+ CARDINALITY(...) */
Oracle은 전달 된 어레이의 카디널리티를 이해하지 못하고 최적의 실행 계획을 예측할 수 없기 때문에 힌트 가 매우 유용합니다.
또 다른 대안으로 임시 테이블에 일괄 삽입하고 IN
술어에 대한 하위 쿼리의 마지막을 사용합니다 .
in
-clause 내부의 내부 쿼리를 사용하십시오 .
select col1, col2, col3... from table1
where id in (select id from table2 where conditions...)
이 문제를 해결하는 다른 방법도 있습니다. 두 개의 테이블 Table1과 Table2가 있다고 가정 해 보겠습니다. Criteria 쿼리를 사용하여 Table2에서 참조 / 표시되지 않은 Table1의 모든 항목을 가져와야합니다. 그러니 이렇게하세요 ...
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 )"));
.
.
. . . Hibernate 프레임 워크에서 변환 된 SQL에 1000 개 이상의 매개 변수를 포함하지 않고 SQL에서 직접 모든 subquery 기능을 수행합니다. 그것은 나를 위해 일했습니다. 참고 : 요구 사항에 따라 SQL 부분을 변경해야 할 수도 있습니다.
나는 이것이 오래된 질문이고 TOAD를 언급한다는 것을 알고 있지만 C #을 사용하여 이것을 코딩해야한다면 for 루프를 통해 목록을 나눌 수 있습니다. subList ()를 사용하여 Java에서도 기본적으로 동일한 작업을 수행 할 수 있습니다.
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);
}
Hope this helps someone.
There is another option: with
syntax. To use the OPs example, this would look like:
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;
I ran into this problem. In my case I had a list of data in Java where each item had an item_id and a customer_id. I have two tables in the DB with subscriptions to items respective customers. I want to get a list of all subscriptions to the items or to the customer for that item, together with the item id.
I tried three variants:
- Multiple selects from Java (using tuples to get around the limit)
- With-syntax
- Temporary table
Option 1: Multiple Selects from Java
Basically, I first
select item_id, token
from item_subs
where (item_id, 0) in ((:item_id_0, 0)...(:item_id_n, 0))
Then
select cus_id, token
from cus_subs
where (cus_id, 0) in ((:cus_id_0, 0)...(:cus_id_n, 0))
Then I build a Map in Java with the cus_id as the key and a list of items as value, and for each found customer subscription I add (to the list returned from the first select) an entry for all relevant items with that item_id. It's much messier code
Option 2: With-syntax
Get everything at once with an SQL like
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
Option 3: Temporary table
Create a global temporary table with three fields: rownr (primary key), item_id and cus_id. Insert all the data there then run a very similar select to option 2, but linking in the temporary table instead of the with data
Performance
This is not a fully-scientific performance analysis.
- I'm running against a development database, with slightly over 1000 rows in my data set that I want to find subscriptions for.
- I've only tried one data set.
- I'm not in the same physical location as my DB server. It's not that far away, but I do notice if I try from home over the VPN then it's all much slower, even though it's the same distance (and it's not my home internet that's the problem).
- I was testing the full call, so my API calls another (also running in the same instance in dev) which also connects to to the DB to get the initial data set. But that is the same in all three cases.
YMMV.
That said, the temporary table option was much slower. As in double so slow. I was getting 14-15 seconds for option 1, 15-16 for option 2 and 30 for option 3.
I'll try them again from the same network as the DB server and check if that changes things when I get the chance.
Operato union
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)
There's also workaround doing disjunction of your array, worked for me as other solutions were hard to implement using some old framework.
select * from tableA where id = 1 or id = 2 or id = 3 ...
But for better perfo, I would use Nikolai Nechai's solution with unions, if possible.
'Development Tip' 카테고리의 다른 글
Linux의 Bash에서 syslog를 확인하는 방법은 무엇입니까? (0) | 2020.11.19 |
---|---|
onReceive BroadcastReceiver 내에서 활동 시작 (0) | 2020.11.19 |
여러 대상이있는 Objective C to Swift 헤더 파일 (0) | 2020.11.19 |
새로운 Typescript 1.8.4 빌드 오류 :“빌드 : 'EventTarget'유형에 'result'속성이 없습니다. (0) | 2020.11.19 |
DateAdd를 사용하여 날짜에 요일을 추가하는 SQL Server 2005 (0) | 2020.11.19 |