it-swarm.asia

هل هناك حل بديل لـ ORA-01795: الحد الأقصى لعدد التعبيرات في القائمة هو 1000 خطأ؟

هل هناك حل للمشكلة

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

لديّ استعلام وهو يقوم باختيار الحقول بناءً على قيمة حقل واحد. أنا أستخدم في جملة وهناك 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 ، لا فرق ، نفس الخطأ. كيف يمكنني تعديل الاستعلام لجعله يعمل؟

شكرا لك مقدما

57
valmont74

استخدم مجرد عبارات متعددة للتغلب على هذا:

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

لقد واجهت هذه المشكلة مؤخرًا واكتشفت طريقة بسيطة للقيام بذلك دون توحيد الجمل الإضافية في الجمل

هل يمكن الاستفادة من Tuples

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

أوراكل يسمح> 1000 Tuples ولكن ليس القيم البسيطة. المزيد عن هذا هنا ،

https://community.Oracle.com/message/3515498#3515498
و
https://community.Oracle.com/thread/958612

هذا بالطبع إذا لم يكن لديك خيار استخدام استعلام فرعي داخل IN للحصول على القيم التي تحتاجها من جدول مؤقت.

21
MangoCrysis

بعض الحلول البديلة هي:

1- انقسام جملة IN إلى جمل متعددة في IN حيث تقل القيم الحرفية عن 1000 وتجمعها باستخدام جمل 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 - استخدام Tuples: الحد الأقصى 1000 ينطبق على مجموعات من العناصر الفردية: (س) في ((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>);
17
Ahmed MANSOUR

طريقة واحدة أخرى:

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 المسند.

7
svaor

الرجاء استخدام استعلام داخلي بداخل جملة in-:

select col1, col2, col3... from table1
 where id in (select id from table2 where conditions...)
7
Vikas Kumar

يوجد خيار آخر: بناء جملة with. لاستخدام مثال OPs ، سيبدو هذا كالتالي:

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;

لقد واجهت هذه المشكلة. في حالتي كان لدي قائمة بيانات في Java حيث كان لكل عنصر item_id و customer_id. لديّ جدولان في قاعدة البيانات مع اشتراكات في عناصر العملاء المعنيين. أرغب في الحصول على قائمة بجميع الاشتراكات في العناصر أو إلى العميل لهذا العنصر ، إلى جانب معرف العنصر.

حاولت ثلاثة أنواع:

  1. اختيارات متعددة من Java (باستخدام tuples للتغلب على الحد الأقصى)
  2. مع تركيب
  3. الجدول المؤقت

الخيار 1: اختيارات متعددة من جافا

أساسا ، أنا أولا

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

ثم

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

ثم أقوم بإنشاء خريطة في Java باستخدام cus_id كمفتاح وقائمة بالعناصر كقيمة ، ولكل إضافة اشتراك عميل تم العثور عليه ، أضف (إلى القائمة التي تم إرجاعها من الاختيار الأول) إدخالًا لجميع العناصر ذات الصلة مع هذا item_id. انها رمز messier بكثير

الخيار 2: مع بناء الجملة

الحصول على كل شيء في وقت واحد مع مزود مثل

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

الخيار 3: الجدول المؤقت

قم بإنشاء جدول مؤقت عالمي بثلاثة حقول: rownr (المفتاح الأساسي) و item_id و cus_id. قم بإدراج جميع البيانات هناك ثم قم بتشغيل تحديد مشابه جدًا للخيار 2 ، ولكن قم بالربط في الجدول المؤقت بدلاً من with data

أداء

هذا هو لا تحليل أداء علمي بالكامل.

  • أقوم بمقابلة قاعدة بيانات تطوير ، مع ما يزيد قليلاً عن 1000 صف في مجموعة البيانات التي أرغب في العثور على اشتراكات لها.
  • لقد جربت مجموعة بيانات واحدة فقط.
  • أنا لست في نفس الموقع الفعلي لخادم DB الخاص بي. الأمر ليس بعيدًا ، لكنني لاحظت إذا ما حاولت من المنزل عبر VPN ، فكل شيء أبطأ بكثير ، على الرغم من أنها المسافة نفسها (وليست الإنترنت المنزلي هي المشكلة).
  • كنت أقوم باختبار المكالمة بالكامل ، لذلك تتصل واجهة برمجة التطبيقات (API) الخاصة بي بأخرى (تعمل أيضًا في نفس الحالة في dev) والتي تتصل أيضًا بقاعدة البيانات للحصول على مجموعة البيانات الأولية. ولكن هذا هو نفسه في الحالات الثلاث.

YMMV.

ومع ذلك ، كان خيار الجدول المؤقت كثير أبطأ. كما هو الحال في ضعف بطيئة جدا. كنت أحصل على 14-15 ثانية للخيار 1 ، 15-16 للخيار 2 و 30 للخيار 3.

سأحاول مرة أخرى من نفس الشبكة مثل خادم قاعدة البيانات وتحقق مما إذا كان ذلك يغير الأشياء عندما أتيحت لي الفرصة.

3
Adam

هناك أيضًا طريقة أخرى لحل هذه المشكلة. لنفترض أن لديك جدولين Table1 و Table2. ويلزم إحضار جميع إدخالات Table1 غير المشار إليها/الحالية في Table2 باستخدام استعلام المعايير. لذلك المضي قدما مثل هذا ...

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 )"));
.
.

. . . سيقوم بتنفيذ جميع وظائف الاستعلام الفرعي مباشرة في SQL دون تضمين 1000 معلمة أو أكثر في SQL التي يتم تحويلها بواسطة إطار السبات. عملت معي. ملاحظة: قد تحتاج إلى تغيير جزء SQL وفقًا لمتطلباتك.

2
Fahim Ashraf

أدرك أن هذا سؤال قديم ويشير إلى TOAD ، لكن إذا كنت بحاجة إلى حل المشكلة باستخدام c # ، فيمكنك تقسيم القائمة إلى حلقة. يمكنك فعل الشيء نفسه باستخدام Java باستخدام 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);
    }

أمل أن هذا يساعد شخصاما.

2
Tyler