قاعدة بيانات أوراكل / الأساسي: أسس العلاقات والمعاملات / الدرس 4
الربط ومستوى تفصيل العلاقات
اجمع العملاء والشحنات والمسوح دون مضاعفة الحقائق أو فقدان العلاقات الخالية.
في هذه الصفحة
أهداف الدرس
- توقّع عدد صفوف الربط انطلاقاً من علاقات المفاتيح.
- حافظ على مقصد الربط الخارجي واستخدم اختبارات الوجود.
سمِّ ما يمثله الصف الواحد
يمثل صف العميل عميلاً واحداً، وصف الشحنة شحنة، وصف المسح حدثاً مسجلاً. يغيّر الربط مستوى تفصيل النتيجة. تنتج شحنة لها ثلاثة مسوح ثلاثة صفوف بعد الربط، رغم أن رسمها حقيقة واحدة. جمع الرسم حينئذ يضاعف الإيراد ثلاث مرات. ارسم علاقة المفاتيح واحسب مثالاً صغيراً يدوياً قبل كتابة SQL. الإجمالي المالي المعقول دليل ضعيف، فقد تعوّض الرسوم المكررة إغفالات أخرى في التقرير المجمع. يجب أن يبقى معنى الصف صحيحاً بعد كل ربط.
اربط بالمفاتيح لا بتشابه الأوصاف
اربط العملاء والشحنات بـcustomer_id لا بـcustomer_name. قد يتشارك عميلان اسماً معروضاً وقد يغيّر العميل اسمه بمرور الوقت. أهّل أسماء الأعمدة المشتركة بأسماء الجداول المستعارة لإظهار الملكية. تفصل صياغة ANSI JOIN شروط العلاقة عن شروط التقرير وتُفضَّل على معامل الربط الخارجي القديم (+). في البيانات التالية تنتمي شحنتان للعميل 7؛ تنتج صفان لأن مفتاح العميل فريد، ولا يُفترض ترتيب سوى المعرّف الصريح.
WITH customers AS (
SELECT 7 customer_id, 'Nile Lab' customer_name FROM dual
), shipments AS (
SELECT 101 shipment_id, 7 customer_id FROM dual UNION ALL
SELECT 102, 7 FROM dual
)
SELECT s.shipment_id, c.customer_name
FROM shipments s JOIN customers c ON c.customer_id = s.customer_id
ORDER BY s.shipment_id;
SHIPMENT_ID | CUSTOMER_NAME
101 | Nile Lab
102 | Nile Lab
تطابق كل شحنة الأب الفريد مرة واحدة. يحتفظ UNION ALL بصفّي الشحن الاصطناعيين.
ضع شروط الجانب الاختياري بعناية
يحفظ الربط الأيسر كل صف في الجانب الأيسر ويضع NULL للجانب الأيمن غير المطابق. لتضمين الشحنات التي ليس لها مسح مقبول، ضع شرط الحالة المقبولة داخل ON. وضعه في WHERE يرفض الصفوف الممددة بـNULL ويشترط وجود تطابق فعلي. قد يصح ذلك لسؤال آخر لكنه يغيّر التقرير. يحسب COUNT(sc.scan_id) الأبناء الفعليين، بينما يحسب COUNT(*) أيضاً صف الأب المحفوظ بلا أبناء. اختر التعبير وفق وحدة العمل المقصودة لا وفق عادة من استعلام أبسط.
SELECT s.shipment_id, COUNT(sc.scan_id) AS accepted_scans
FROM shipments s
LEFT JOIN scans sc
ON sc.shipment_id = s.shipment_id AND sc.status = 'accepted'
GROUP BY s.shipment_id
ORDER BY s.shipment_id;
تظهر كل شحنة مرة بعد التجميع. الشحنة التي لا تملك مسحاً مقبولاً لها accepted_scans = 0.
اسأل عن الوجود دون إظهار كل ابن
عندما تحتاج النتيجة صفاً لكل شحنة لديها مسح استثنائي واحد على الأقل، يعبّر EXISTS مباشرة عن المقصد. قد يخفي الربط المتبوع بـDISTINCT مضاعفة غير مقصودة، وقد يتغير المعنى عند إضافة أعمدة الأبناء. يعبّر NOT EXISTS عن غياب التطابق دون فخ المجموعة القابلة لـNULL في NOT IN. لا تفرض هذه الصيغ خوارزمية مادية واحدة؛ يمكن للمحسّن تحويلها. قيّم وضوحها الدلالي أولاً ثم افحص أدلة الخطة المصرح بها للأداء، ولا تستنتج عمل المحرك من طول النص فقط.
جمّع مجموعات الأبناء المستقلة أولاً
افترض أن لشحنة ثلاثة مسوح وسطرَي فاتورة. ينتج ربط جدولَي الأبناء الخام ستة تراكيب. يمنع تجميع كل مجموعة إلى shipment_id قبل الربط هذا الضرب التبادلي. يجب توثيق ضمان التفرّد لكل نتيجة وسيطة على مفتاح الربط. يسهّل التعبير الجدولي المشترك المراجعة لكنه لا يضمن التجسيد أو إزالة كل العمل. احتفظ ببيانات مطابقة فيها أب له عدة صفوف في المجموعتين، وآخر بلا أبناء، وثالث بمجموعة واحدة؛ فهي تكشف عيوباً تخفيها أمثلة الصف الواحد.
الأخطاء الشائعة وإصلاحها
ORA-00918
- لماذا يحدث؟
- ذُكر عمود مشترك دون اسم مستعار مؤهّل.
- كيف تصلحه؟
- أهّل المالك المقصود في الأعمدة والشروط والترتيب.
- كيف تتجنب تكراره؟
- استخدم أسماء مستعارة قصيرة ومتسقة عند مشاركة عدة جداول.
تختفي الشحنات التي لا تملك مسوحاً
- لماذا يحدث؟
- يرفض شرط الجانب الأيمن في WHERE صفوف NULL للربط الخارجي.
- كيف تصلحه؟
- انقل شرط الابن إلى ON إذا كان حفظ الأب مطلوباً.
- كيف تتجنب تكراره؟
- اختبر أباً بلا أبناء مطابقين في كل تقرير ربط خارجي.
يزداد الإيراد عند إضافة أعمدة المسوح
- لماذا يحدث؟
- كرر ربط واحد إلى متعدد الرسوم على مستوى الشحنة.
- كيف تصلحه؟
- جمّع كل ابن إلى التفصيل المطلوب قبل دمج الحقائق المالية.
- كيف تتجنب تكراره؟
- اكتب معنى الصف الواحد بجوار كل مرحلة تقرير.
اختبر فهمك
1. لشحنة أربعة مسوح وثلاثة أسطر فاتورة. كم تركيباً ينتج عن الربط الخام؟
اعرض الحل المشروح
اثنا عشر؛ يقترن كل مسح بكل سطر فاتورة ويظهر رسم الشحنة اثنتي عشرة مرة. جمّع كل مجموعة أبناء مستقلة إلى صف لكل شحنة وتحقق من تفرّد المفتاح ثم اربط الملخصات بالأب. ليست DISTINCT على الإجمالي المالي النهائي معالجة سليمة.
2. هل ينبغي لتقرير العملاء بلا شحنات استخدام ربط داخلي؟
اعرض الحل المشروح
لا؛ استخدم NOT EXISTS مع مفتاح العميل، أو ربطاً أيسر مضبوطاً واختبار NULL على مفتاح ابن غير قابل لـNULL. يوضح EXISTS متطلب الغياب ويتجنب تكرار العملاء. اختبر عميلاً بلا أبناء وآخر له عدة أبناء.
أهم ما تعلمته
- عدد علاقات الربط جزء من نتيجة العمل.
- يحفظ الربط الخارجي الصفوف إذا احترمت الشروط اللاحقة هذا المقصد.