سؤال

عثر مديري على خطأ في استعلام قمت بإنشائه، ولا أفهم السبب وراء الخطأ، على الرغم من أن نتائج الاستعلام تثبت صحته.إليك الاستعلام (نسخة مبسطة) قبل الإصلاح:

select PTNO,PTNM,CATCD
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD); 

وهنا بعد الإصلاح:

select PTNO,PTNM,PARTS.CATCD
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD); 

كان الخطأ هو أنه تم عرض القيم الخالية للعمود CATCD، أي.تضمنت نتائج الاستعلام نتائج من فئات الجدول بدلاً من الأجزاء.إليك ما لا أفهمه:إذا كان هناك غموض في الاستعلام الأصلي، فلماذا لم ترتكب Oracle خطأً؟بقدر ما فهمت، في حالة الصلات اليسرى، يكون للجدول "الرئيسي" في الاستعلام (PARTS) الأسبقية في الغموض.هل أنا مخطئ أم أنني لا أفكر في هذه المشكلة بشكل صحيح؟

تحديث:

فيما يلي مثال منقح، حيث لم يتم طرح خطأ الغموض:

CREATE TABLE PARTS (PTNO NUMBER, CATCD NUMBER, SECCD NUMBER);

CREATE TABLE CATEGORIES(CATCD NUMBER);

CREATE TABLE SECTIONS(SECCD NUMBER, CATCD NUMBER);


select PTNO,CATCD 
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD) 
left join SECTIONS on (SECTIONS.SECCD=PARTS.SECCD) ;

أي شخص لديه فكرة؟

هل كانت مفيدة؟

المحلول

أخشى أنني لا أستطيع أن أخبرك لماذا لم تحصل على استثناء، ولكن يمكنني افتراض سبب اختيار إصدار العمود CATEGORIES على إصدار PARTS.

بقدر ما فهمت، في حالة الصلات اليسرى، يكون للجدول "الرئيسي" في الاستعلام (PARTS) الأسبقية في الغموض

ليس من الواضح ما إذا كنت تقصد بكلمة "رئيسي" ببساطة الجدول الأيسر في صلة يسارية، أو جدول "القيادة"، كما ترى الاستعلام من الناحية المفاهيمية...ولكن في كلتا الحالتين، فإن ما تراه على أنه الجدول "الرئيسي" في الاستعلام كما كتبته لن يكون بالضرورة الجدول "الرئيسي" في التنفيذ الفعلي لهذا الاستعلام.

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

نصائح أخرى

إليك الاستعلام (نسخة مبسطة)

أعتقد أنه من خلال تبسيط الاستعلام قمت بإزالة السبب الحقيقي للخطأ :-)

ما هو إصدار أوراكل الذي تستخدمه؟أوراكل 10 جرام (10.2.0.1.0) يعطي:

create table parts (ptno number , ptnm number , catcd number);  
create table CATEGORIES (catcd number);

select PTNO,PTNM,CATCD from PARTS  
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);

أحصل على ORA-00918:تعريف العمود غامضة

من المثير للاهتمام في خادم SQL الذي يلقي خطأ (كما ينبغي)

select id
from sysobjects s
left join syscolumns c on s.id = c.id

الخادم:MSG 209 ، المستوى 16 ، الحالة 1 ، السطر 1 اسم العمود الغامض "معرف".

select id
from sysobjects 
left join syscolumns  on sysobjects.id = syscolumns.id

الخادم:MSG 209 ، المستوى 16 ، الحالة 1 ، السطر 1 اسم العمود الغامض "معرف".

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

لذا، نظرًا لأن هذا الارتباط سيحتوي على كافة السجلات من الأجزاء مع بعض السحب فقط من الفئات، سيكون لديك NULL في حقل CATCD في أي وقت لا توجد فيه بيانات على الجانب الأيمن.

من خلال تحديد العمود بشكل صريح من PARTS (أي الجانب الأيسر) سوف تحصل على قيمة غير فارغة بافتراض أن الحقل يحتوي على بيانات في PARTS.

تذكر أنه مع LEFT JOIN، فأنت فقط بيانات مضمونة في الحقول الموجودة في الجدول الأيسر، وقد تكون هناك أعمدة فارغة على اليمين.

قد يكون هذا خطأ في مُحسِّن Oracle.يمكنني إعادة إنتاج نفس السلوك في الاستعلام باستخدام 3 جداول.يبدو بديهيًا أنه يجب أن ينتج خطأً.إذا قمت بإعادة كتابتها بأي من الطرق التالية، فسيؤدي ذلك إلى حدوث خطأ:

(1) استخدام الصلة الخارجية ذات النمط القديم

select ptno, catcd
from parts, categories, sections
where categories.catcd (+) = parts.catcd
  and sections.seccd (+) = parts.seccd

(2) عزل الوصلتين صراحة

select ptno, catcd
from (
  select ptno, seccd, catcd
  from parts
  left join categories on (categories.CATCD=parts.CATCD) 
)
left join sections on (sections.SECCD=parts.SECCD)

لقد استخدمت DBMS_XPLAN للحصول على تفاصيل حول تنفيذ الاستعلام، والذي أظهر شيئًا مثيرًا للاهتمام.تتمثل الخطة بشكل أساسي في ربط الأجزاء والفئات خارجيًا، وعرض مجموعة النتائج تلك، ثم ربطها خارجيًا بالأقسام.الجزء المثير للاهتمام هو أنه في إسقاط الصلة الخارجية الأولى، فهو يتضمن فقط PTNO وSECCD - ولا يتضمن CATCD من أي من الجدولين الأولين.وبالتالي فإن النتيجة النهائية هي الحصول على CATCD من الجدول الثالث.

لكن لا أعلم هل هذا سبب أم نتيجة؟

أنا أستخدم أوراكل 9.2.0.8.0.ويعطي الخطأ "ORA-00918:تعريف العمود غامضة".

يعد هذا خطأ معروفًا في بعض إصدارات Oracle عند استخدام صلات نمط ANSI.سيكون السلوك الصحيح هو الحصول على خطأ ORA-00918.

من الأفضل دائمًا تحديد أسماء الجداول الخاصة بك على أي حال؛وبهذه الطريقة لا تنقطع استعلاماتك عندما تقوم بإضافة عمود جديد باسم يستخدم أيضًا في جدول آخر.

يُنصح بشكل عام بأن تكون محددًا وأن تقوم بتأهيل جميع أسماء الأعمدة بشكل كامل على أي حال، حيث أن ذلك يوفر على المُحسِّن القليل من العمل.بالتأكيد في SQL Server.

مما أستطيع استخلاصه من مستندات أوراكل, ، يبدو أنه لن يتم تنفيذه إلا إذا قمت بتحديد اسم العمود مرتين في قائمة التحديد، أو مرة واحدة في قائمة التحديد ثم مرة أخرى في مكان آخر مثل الترتيب حسب الجملة.

ربما تكون قد اكتشفت "ميزة غير موثقة" :)

مثل HollyStyles، لا يمكنني العثور على أي شيء في مستندات Oracle يمكنه شرح ما تراه.

يرفض كل من PostgreSQL وDB2 وMySQL وMSSQL تشغيل الاستعلام الأول، لأنه غامض.

@تربيتة:أحصل على نفس الخطأ هنا لاستعلامك.استعلامي أكثر تعقيدًا قليلاً مما نشرته في الأصل.أنا أعمل على مثال بسيط قابل للتكرار الآن.

السؤال الأكبر الذي يجب أن تطرحه على نفسك هو - لماذا لدي رمز فئة في جدول الأجزاء غير موجود في جدول الفئات؟

هذا خطأ في Oracle 9i.إذا قمت بضم أكثر من جدولين باستخدام تدوين ANSI، فلن يكتشف الغموض في أسماء الأعمدة، ويمكنه إرجاع العمود الخطأ إذا لم يتم استخدام اسم مستعار.

كما ذكرنا سابقًا، تم إصلاحه في 10 جرام، لذا إذا لم يتم استخدام اسم مستعار، فسيتم إرجاع خطأ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top