SQLite / الأساسي: المحرك المضمّن والبيانات الصحيحة / الدرس 5
الربط والملخصات المجمعة الموثوقة
اجمع صفوف SQLite مع تتبع تعدد المطابقات والغياب ومقامات التجميع والفرق بين شروط الصف وشروط المجموعة.
في هذه الصفحة
أهداف الدرس
- توقع خرج علاقة واحد لمتعدد قبل جمع القياسات.
- الحفاظ على الآباء غير المطابقين بقواعد ربط خارجي صريحة.
- تحديد GROUP BY و COUNT و HAVING وفق وحدة النتيجة المقصودة.
ينشئ الربط تركيبات مطابقة لا عدداً مفترضاً للكيانات
يظهر العميل ذو الطلبين مرتين عند ربطه بصفوف الطلب. هذا سلوك واحد لمتعدد متوقع وليس تكرار عملاء خاطئاً تلقائياً. اكتب وحدة الخرج قبل إضافة مجموع؛ فربط الرأس ببنوده يكرر مبلغه، وقد يضاعف تفصيل مستقل آخر التكرار. استخدم المفاتيح للعلاقات بدلاً من أسماء العرض التي قد تتشابه أو تتغير.
يحفظ INNER JOIN المطابقات، ويضيف LEFT JOIN كل صف يساري غير مطابق بقيم يمينية مفقودة. ينتج CROSS JOIN كل التركيبات عمداً وقد يفيد لمصفوفة اختبار صغيرة، لكن غياب شرط العلاقة قد يفجر العدد عرضاً. افحص تكرار المطابقة لكل مفتاح وقارنه بالعلاقة المقصودة، ولا تثق باسم عمود مألوف وحده.
احفظ الأب الذي لا يملك صفاً تابعاً
ينشئ المثال عميلين وطلبين للأول، فتنتج ثلاثة صفوف: مطابقتان وصف للثاني موسع بقيم مفقودة. يجعل الترتيب النتيجة قابلة للفحص. يصلح مفتاح يميني غير قابل للغياب مؤشراً للمطابقة؛ فقد تكون صفة اختيارية مفقودة حتى في طلب موجود فعلاً.
إذا لزم إبقاء كل العملاء وإرفاق المفتوح فقط، فضع شرط تأهيل الابن في ON. ترفض WHERE التي تشترط حالة مفتوحة الصف غير المطابق لأن مقارنته مجهولة. يجيب الموضعان سؤالين مختلفين رغم بقاء LEFT JOIN، ويمكن لـ EXISTS سؤال الوجود دون مضاعفة العميل الخارجي بعدد طلباته.
CREATE TABLE customer(id INTEGER PRIMARY KEY);
CREATE TABLE purchase(id INTEGER PRIMARY KEY,customer_id INTEGER);
INSERT INTO customer VALUES(1),(2);
INSERT INTO purchase VALUES(10,1),(11,1);
SELECT c.id AS customer,p.id AS purchase FROM customer AS c
LEFT JOIN purchase AS p ON p.customer_id=c.id ORDER BY c.id,p.id;
customer|purchase
1|10
1|11
2|NULL
للعميل 1 طلبان مطابقان، وللعميل 2 صف محفوظ بمفتاح طلب NULL. يفسر العقد ثلاثة صفوف بدلاً من افتراض صف لكل عميل.
حدد الوحدة الجديدة التي ينشئها GROUP BY
تنتج GROUP BY صفاً لكل تركيب متميز من المفاتيح. استخدم معرف العميل المستقر كي لا تدمج أشخاصاً يشتركون في الاسم، واختر تعبيرات تجميع ودوال ذات معنى. قد تعيد ميزة العمود غير المجمّع في SQLite قيمة اعتباطية لا تبرر وصف المجموعة؛ فلا تستبدل بها تعريف الوحدة.
تعد COUNT(*) الصفوف وتعد COUNT(amount) المبالغ المعروفة، وتتجاهل SUM و AVG المفقود وفق قواعدهما. قد تختلف نتيجة المدخل الفارغ من الصفر، وتحتاج المجموعة المفقودة كلها سياسة. يغير إحلال الصفر قبل المتوسط المقام والمعنى، لذلك اعرض تغطية القياس عندما يكون الغياب مهماً للسؤال.
رشح صفوف المصدر قبل اختبار المجموعات
تحدد WHERE عضوية مدخل التجميع، وتختار HAVING المجموعات المكتملة. يجمع المثال الطلبين المفتوحين 30 و 40 إلى 70 فيتأهلان، ولا يشارك المغلق 200. يحذف شرط مبلغ فردي فوق 50 المساهمتين الصحيحتين. الفرق هنا تعريف للمجتمع، لا تفضيل للمحسن أو اختيار أسلوبي بلا أثر.
يمكن للتجميع المشروط بـ CASE حساب مقاييس متعددة إذا صُرّح بمقام كل منها وغيابه. ويهم التمثيل العددي أيضاً: تحفظ الوحدات الصغرى الصحيحة الحساب الدقيق ضمن المدى، وتظل REAL تقريبية. تحقق من المجاميع الضابطة والصفوف المؤهلة قبل تحديد المنازل التي يعرضها التقرير.
CREATE TABLE purchase(customer INTEGER,status TEXT,amount INTEGER);
INSERT INTO purchase VALUES(1,'open',30),(1,'open',40),
(1,'closed',200),(2,'open',25),(2,'open',NULL);
SELECT customer,COUNT(*) AS orders,COUNT(amount) AS known,SUM(amount) AS total
FROM purchase WHERE status='open' GROUP BY customer
HAVING SUM(amount)>50 ORDER BY customer;
customer|orders|known|total
1|2|2|70
يتأهل العميل 1 بطلبين مفتوحين معروفين مجموعهما 70. يستبعد شرط الحالة الطلب المغلق قبل التجميع، ولا يشارك في المجموع.
استخدم أمثلة مضادة صغيرة وطابق المجاميع
اختبر أباً بلا أبناء وآخر بابن وثالثاً بعدة أبناء، وأضف مبالغ متساوية وصفة اختيارية مفقودة. لا تصلح SUM(DISTINCT header.amount) تضاعف الربط؛ إذ تختزل طلبين صحيحين متساويين إلى قيمة واحدة. جمّع كل تفصيل إلى الوحدة المطلوبة، أو احسب قياسات الرأس مستقلة قبل دمج الملخصات.
طابق أعداد المجموعات ومبالغها بصفوف الأساس ذات التصفية نفسها. وثق التغطية والاستبعادات للفئات المهمة لا نسبة المطابقة الكلية فقط. قد يتسق التقرير حسابياً ويمثل أشخاصاً أو أحداثاً خطأ. اشرح الوحدة وعلاقة المفتاح والعضوية والدالة ومعالجة المجهول معاً حتى يستطيع قارئ آخر تدقيق الملخص.
الأخطاء الشائعة وإصلاحها
زاد مجموع الرأس بعد ربط التفاصيل.
- لماذا يحدث؟
- كررت علاقة واحد لمتعدد القياس مرة لكل مطابقة.
- كيف تصلحه؟
- جمّع القياس عند وحدته المالكة قبل إضافة تفاصيل مستقلة.
- كيف تتجنب تكراره؟
- تتبع عدد المطابقات بعد كل مرحلة ربط.
اختفى أب كان يفترض إبقاءه.
- لماذا يحدث؟
- رفض شرط WHERE صف الابن الموسع بالقيم المفقودة.
- كيف تصلحه؟
- ضع تأهيل الابن في ON عندما تكون المحافظة على الأب مقصودة.
- كيف تتجنب تكراره؟
- اختبر أباً بلا أبناء مؤهلين.
وصفت تسمية المجموعة صفاً اعتباطياً.
- لماذا يحدث؟
- عُد عمود غير مجمّع خاصية مضمونة للمجموعة كلها.
- كيف تصلحه؟
- اختر مفاتيح مبررة أو دالة تلائم الخاصية المقصودة.
- كيف تتجنب تكراره؟
- حدد وحدة الخرج قبل اختيار أعمدته.
اختبر فهمك
1. لطلب قيمته 20 بندان وثلاث دفعات مستقلة. ما عدد التركيبات ومجموع الرأس المتكرر؟
اعرض الحل المشروح
قد ينتج الربط 2×3=6 صفوف ومجموعاً متكرراً 120، بينما يبقى مبلغ الطلب الحقيقي 20. لخص التفاصيل منفصلة على مستوى الطلب؛ ولا تصلح DISTINCT على القيمة هوية الكيان عموماً، لأنها قد تدمج مبالغ متساوية لطلبات صحيحة مختلفة.
2. لماذا يفسد WHERE amount>50 سؤال مجموع المفتوح 30 و 40 مع مغلق 200؟
اعرض الحل المشروح
يرشح الشرط القيم الفردية ويحذف الطلبين المفتوحين اللذين يجب أن يساهما. رشح حالة المفتوح ثم جمّع بالعميل وطبق HAVING SUM(amount)>50 لتحصل على 70. حدد أيضاً هل يعد المبلغ المفقود طلباً دون اعتباره قياساً معروفاً.
أهم ما تعلمته
- يغير الربط تعددية الصفوف، ويغير التجميع وحدة النتيجة.
- موضع شرط الربط ومقام الدالة قراران في المعنى.
- تكشف المطابقة أخطاء لا يكشفها نجاح تنفيذ الاستعلام.