Interview Handbook by Sayed Elmahdy English

المحور 13 · الداتا وقواعد البيانات

Relational Algebra ونظرية قواعد البيانات

σ و π و ⋈، وإزاي بتتحوّل لـ SQL، و Query optimizer، و Functional dependencies، و Keys.

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

15 سؤالJunior · 4Mid · 7Senior · 410 اختيارات

المفاهيم

هنفهم إيه؟ هتفك استعلام لخطوات واضحة: صفوف بنختارها، أعمدة بنعرضها، وعلاقات بنربطها. ده يساعدك تكتشف ليه join كرر order أو ليه إجمالي الفاتورة طلع أكبر من المتوقع، قبل ما تغيّر الاستعلام أو تحسّنه.

قبل ما تبدأ: الجدول مجموعة صفوف، وكل صف فيه قيم تحت أعمدة مسماة؛ المفتاح عمود أو مجموعة أعمدة تميّز الصف. لو كتبت SQL بسيطة، هتقدر تربط الرموز بأوامر مألوفة. مافيش احتياج لدراسة رياضيات متقدمة، والأمثلة هتشرح كل رمز وقت ظهوره.

المصطلحات اللي تحتها خط منقّط تقدر تضغط عليها لمعرفة معناها، وترجع تكمل من نفس مكانك.

#Bonus: ليه مهندس .NET يحتاج Relational Algebra؟BonusBonus: why relational algebra matters to a .NET engineer

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

Query بترجع أرقام غلط حتى لو صحيحة نحويًا؟ غالبًا المشكلة في معنى join أو التكرار أو مكان filter. Relational algebra بتديك لغة صغيرة تفك بيها الاستعلام لعمليات، وتراجع SQL مولّدة من أو . المحور كله اختياري؛ الهدف تفهم النتيجة قبل ما تناقش سرعة التنفيذ.

Relation مجموعة tuples بنفس . الـ tuple صف، والـ attribute عمود مسمّى، والـ domain مجموعة القيم المسموحة للعمود. الـ relation النظرية ملهاش ترتيب أو duplicates؛ SQL table ممكن يبقى فيها تكرار و. الأمثلة الجبرية هنا set semantics، والـ SQL بيستخدم DISTINCT لما الفرق مهم.

Products.IdNameCategoryPrice
1BookBooks100
2PenOffice20
3NotebookBooks60
SELECT Id, Name FROM Products ORDER BY Id; -- (1)
🧾 شرح الكود
  1. (1) الـ ORDER BY ضمان عرض في SQL، مش خاصية في الـ relation. من غيره ماتعتمدش على ترتيب وصول الصفوف.
استخدم النظرية كأداة مراجعة: إيه صفوف الإدخال؟ كام صف ممكن يخرج؟ إيه الـ key؟ مش محتاج تكتب رموز في كل .

#σ و π و ρ: اختار الصفوف والأعمدة والأساميBonusσ, π and ρ: rows, columns and names

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

مثال خطوة بخطوة
  1. افترض جدول Products بأعمدة Id وName وPrice، ومنتجين سعرهما 50 و150. المطلوب أسماء المنتجات الأغلى من 100.
  2. Selection بالرمز σ تختار الصفوف حسب الشرط: يتبقى صف المنتج ذي السعر 150. بالرمز π تختار الأعمدة: يتبقى عمود Name فقط.
  3. افتكر الفرق: selection تسأل أنهي صفوف؟ projection تسأل أنهي أعمدة؟ في ، WHERE تقابل شرط الصفوف وSELECT تحدد شكل الأعمدة، مع فروق مثل التكرارات و نشرحها لاحقًا.

لما شاشة المنتجات محتاجة أسماء الكتب بس، ماتحمّلش كل الصفوف والأعمدة. Selection σ بتفلتر صفوف. Projection π بتختار attributes وبتشيل تكرار في الجبر. Rename ρ بتسمي relation أو attributes عشان تمنع الالتباس، خصوصًا self joins.

Expressionالنتيجة من Products
σ Category='Books' (Products)الصفين 1 و3 بكل الأعمدة
π Category (Products)Books وOffice مرة واحدة لكل قيمة
ρ P (Products)نفس الداتا تحت اسم P
SELECT * FROM Products WHERE Category = 'Books';       -- (1) σ
SELECT DISTINCT Category FROM Products;               -- (2) π
SELECT P.Id AS ProductId, P.Name FROM Products AS P;   -- (3) ρ
🧾 شرح الكود
  1. (1) WHERE أقرب لـ selection رغم إن كلمة SELECT في SQL شكلها مشابه.
  2. (2) DISTINCT مطلوبة لمعادلة projection النظرية؛ SELECT عادية مش بتشيل التكرار.
  3. (3) aliases بتغير الاسم اللي بنشير بيه من غير تعديل البيانات المخزنة.

ماتشيلش join key بدري لو محتاجه بعدين. DISTINCT ممكن تخبي bug في join؛ افهم سبب التكرار الأول.

#∪ و − و ∩: عمليات المجموعاتBonus∪, − and ∩: set operations

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

عايز مستخدمين اشتروا الشهر ده أو الشهر اللي فات؟ دي union. عايز اللي في الاتنين؟ intersection. عايز اللي اشتروا قبل كده ومارجعوش؟ difference. لازم المدخلات union-compatible: نفس عدد الأعمدة وdomains متوافقة، ونوحد الأسامي عند الحاجة.

A(UserId)B(UserId)A ∪ BA − BA ∩ B
1, 22, 31, 2, 312
SELECT UserId FROM A UNION SELECT UserId FROM B;       -- (1)
SELECT UserId FROM A EXCEPT SELECT UserId FROM B;      -- (2)
SELECT UserId FROM A INTERSECT SELECT UserId FROM B;   -- (3)
🧾 شرح الكود
  1. (1) UNION بتشيل duplicates حتى لو موجودة في نفس المدخل.
  2. (2) EXCEPT هي difference؛ الاتجاه مهم: B − A هتطلع 3.
  3. (3) INTERSECT بتحتفظ بالمشترك مرة واحدة.

لو التكرار مقصود، UNION ALL أوفر من إزالة تكرار مش مطلوبة. الجمع هنا بين نتائج، مش join بيزوّد أعمدة. تفاصيل : Combining queries.

#× و ⋈: من كل الأزواج للـ joinsBonus× and ⋈: from all pairs to joins

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

Cartesian product × بيكوّن كل زوج ممكن. لو P فيها صفين وO فيها تلاتة، النتيجة ستة. Theta join هي selection على product بشرط θ؛ equi-join حالتها لما الشرط مساواة. Natural join بتساوي تلقائيًا كل attributes المشتركة في الاسم وبتحتفظ بنسخة واحدة منها؛ زيادة عمود بنفس الاسم ممكن تغيّر النتيجة فجأة.

P(Id, Price)O(OrderId, ProductId, MaxPrice)
(1,100), (2,20)(10,1,120), (11,1,80), (12,9,30)
Expressionالنتيجة
P × O6 أزواج
P ⋈ P.Id=O.ProductId O(1,10) و(1,11) كأزواج IDs
P ⋈ P.Price<O.MaxPrice O(1,10) و(2,10) و(2,11) و(2,12)
SELECT P.Id, O.OrderId FROM P CROSS JOIN O;                 -- (1)
SELECT P.Id, O.OrderId FROM P
JOIN O ON P.Id = O.ProductId;                              -- (2)
SELECT P.Id, O.OrderId FROM P
JOIN O ON P.Price < O.MaxPrice;                            -- (3)
-- Natural join equivalent with explicit matching names after rename:
SELECT P.Id, P.Price, O.OrderId, O.MaxPrice
FROM P JOIN O ON P.Id = O.ProductId;                       -- (4)
🧾 شرح الكود
  1. (1) الـ بتعرض IDs بس؛ الـ product الكامل فيه كل الأعمدة.
  2. (2) المساواة تسمح بأكتر من order لنفس product.
  3. (3) θ ممكن تكون مقارنة غير مساواة.
  4. (4) بعد rename بتاع ProductId إلى Id يبقى ده معنى natural join لو Id هو الاسم المشترك الوحيد. Server مافيهوش NATURAL JOIN؛ الشرط الصريح أوضح ومحمول.

راجع قبل SUM؛ join واحد لمتعدد ممكن يكرر مبلغ order على كل سطر. ماتكتبش CROSS JOIN لو المطلوب relationship بشرط.

#Outer joins و ⋉ و ▷: موجود ولا مش موجود؟BonusOuter joins, ⋉ and ▷: matching and absence

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

تخيّل Users على الشمال وOrders على اليمين: الـ join بيربط صفوف لما قيمة المفتاح في الجدولين تتطابق. Inner join بيرجع المطابق بس. Left outer join بيحافظ على كل مستخدم حتى لو ماعندوش order، ويحط مكان بيانات order الغايبة؛ NULL هنا علامة «مفيش قيمة مطابقة»، مش صفر. Right بيعكس الجهة، وfull بيحافظ على الصفوف غير المطابقة من الناحيتين. دي امتدادات للجبر الكلاسيكي اللي مافيهوش NULL. Semi-join ⋉ يرجّع المستخدمين اللي عندهم order من غير أعمدة order أو تكرار لو للمستخدم كذا order. Anti-join ▷ هنا يرجّع المستخدمين اللي مالهمش order؛ الرمز بيختلف بين المراجع.

Users(Id)Orders(Id, UserId)Users ⋉ OrdersUsers ▷ Orders
1, 2(10,1), (11,1), (12,3)12

Left join تطلع (1,10) و(1,11) و(2,NULL). Right تطلع كمان (NULL,12) بدل (2,NULL). Full تطلع الأربعة.

SELECT U.Id, O.Id AS OrderId FROM Users U
LEFT JOIN Orders O ON O.UserId = U.Id;                     -- (1)
SELECT U.Id, O.Id AS OrderId FROM Users U
RIGHT JOIN Orders O ON O.UserId = U.Id;
SELECT U.Id, O.Id AS OrderId FROM Users U
FULL OUTER JOIN Orders O ON O.UserId = U.Id;
SELECT U.Id FROM Users U WHERE EXISTS
    (SELECT 1 FROM Orders O WHERE O.UserId = U.Id);         -- (2)
SELECT U.Id FROM Users U WHERE NOT EXISTS
    (SELECT 1 FROM Orders O WHERE O.UserId = U.Id);         -- (3)
🧾 شرح الكود
  1. (1) NULL معناها مفيش order مطابق، مش order برقم صفر.
  2. (2) EXISTS تختبر الوجود، ومش محتاجة DISTINCT عشان user 1 عنده orderين.
  3. (3) NOT EXISTS تختبر الغياب من غير فخ NULL بتاع NOT IN.

حط فلتر اليمين في ON لو عايز تحافظ على الصفوف غير المطابقة؛ شرط WHERE O.Status = 'Paid' بعد left join بيستبعد NULL وغالبًا يغيّر المعنى لـ inner join.

#÷ و γ: كل المطلوب والمجاميعBonus÷ and γ: all required items and aggregation

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

Division ÷ تجاوب على «مين اشترى كل المنتجات المطلوبة؟». لو Bought(UserId, ProductId) وRequired(ProductId)، النتيجة Users اللي عندهم زوج مع كل Required. Aggregation γ من extended algebra: تعمل grouping وتحسب count أو sum.

Bought(UserId, ProductId)Required(ProductId)Bought ÷ Required
(1,10), (1,20), (2,10)10, 20UserId = 1
-- Candidate users are the users occurring in Bought, as in division.
SELECT DISTINCT B.UserId FROM Bought B
WHERE NOT EXISTS (
    SELECT 1 FROM Required R
    WHERE NOT EXISTS (
        SELECT 1 FROM Bought B2
        WHERE B2.UserId = B.UserId AND B2.ProductId = R.ProductId)); -- (1)

-- γ UserId; COUNT(*)→ItemCount (Bought)
SELECT UserId, COUNT(*) AS ItemCount
FROM Bought GROUP BY UserId;                                   -- (2)
🧾 شرح الكود
  1. (1) «مفيش منتج مطلوب مش مشترَاه» هي صيغة every. لو Required فاضية، كل user موجود في Bought ينجح؛ لو عايز كل Users حتى اللي مااشترتش، غيّر مجموعة المرشحين ووضّح المعنى.
  2. (2) النتيجة (1,2) و(2,1). لو Bought فيها duplicates، COUNT(*) تعدها؛ استخدم COUNT(DISTINCT ProductId) لو قصدك المنتجات المختلفة.

بديل GROUP BY مع HAVING محتاج يتعامل صح مع duplicates والـ required set الفاضية. Division مش قسمة أرقام، ومش ضرورية لو المطلوب «أي منتج»؛ EXISTS واحدة تكفي.

#Equivalences و Query trees: الـ optimizer بيفكر إزايBonusEquivalences and query trees: optimizer reasoning

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

لو الاستعلام بيعمل join لمليون order وبعدها يفلتر paid، ممكن يدفع selection لتحت قبل join ويقلل الصفوف الوسيطة. دي equivalence منطقية، مش وعد بخطة physical معينة. الـ optimizer بيوازن statistics وindexes وتكلفة join algorithms.

Equivalenceالشرط
σp(σq(R)) = σp∧q(R)filters عادية من غير side effects
σp(R ⋈ S) = (σp(R)) ⋈ Sp بتعتمد على R بس، وinner join
R ⋈ S ≡ S ⋈ Rinner join مع الحفاظ على الأسامي والشروط والـ output
(R ⋈ S) ⋈ T ≡ R ⋈ (S ⋈ T)inner joins وشروط متعاد توزيعها صح
Before:                             After:
π U.Name, O.Id                      π U.Name, O.Id
       |                                   |
σ O.Status='Paid'                         ⋈ U.Id=O.UserId
       |                                /               \
⋈ U.Id=O.UserId                       Users       σ Status='Paid'   (1)
 /           \                                          |
Users       Orders                                    Orders
SELECT U.Name, O.Id FROM Users U
JOIN Orders O ON U.Id = O.UserId
WHERE O.Status = 'Paid';                         -- (2)
🧾 شرح الكود
  1. (1) الفلتر متعلق بـ Orders بس؛ يقدر يتحرك تحت inner join.
  2. (2) الـ نفسها ممكن تتنفذ بالخطة المحسنة؛ مش لازم تعيد كتابتها كـ subquery عشان «تجبر» الترتيب.

ماتطبقش القواعد عمياني على outer joins، أو LIMIT، أو aggregates، أو expressions غير حتمية. pushdown لازم تسيب keys وattributes المستخدمة في filters والـ joins. راجع actual plan بدل الحكم من شكل SQL.

#SQL bags و NULL: الفرق اللي بيكسر الترجمةBonusSQL bags and NULL: where direct translation breaks

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

افتراضيًا bag، يعني التكرار جزء من المعنى. لو الأسعار 20 و20 و100، SELECT Price ترجع تلاتة، و النظرية ترجع 20 و100 بس. الـ join بيضاعف multiplicities، فـ DISTINCT في آخر query ممكن يخبي الخطأ من غير ما يصلح SUM اتحسبت قبلها.

مش قيمة مجهولة تساوي نفسها. المقارنة بيها عادة ترجع ، وWHERE وHAVING بيحتفظوا بـ TRUE بس. NOT UNKNOWN تفضل UNKNOWN. FALSE AND UNKNOWN تساوي FALSE، وTRUE OR UNKNOWN تساوي TRUE.

ExpressionResult
NULL = NULLUNKNOWN
5 NOT IN (1, NULL)UNKNOWN
NULL IS NULLTRUE
COUNT(*) / COUNT(Price)All rows / non-NULL Price rows
SELECT Price FROM Products;                         -- (1) preserves duplicates
SELECT DISTINCT Price FROM Products;
SELECT UserId FROM A UNION ALL SELECT UserId FROM B; -- (2) preserves duplicates
SELECT Id FROM Products WHERE Price IS NULL;        -- (3)
SELECT U.Id FROM Users U WHERE NOT EXISTS (
    SELECT 1 FROM Orders O WHERE O.UserId = U.Id);    -- (4)
🧾 شرح الكود
  1. (1) SELECT وSELECT DISTINCT مش نفس العملية.
  2. (2) UNION ALL تحتفظ بكل النسخ.
  3. (3) IS NULL هي اختبار الغياب، مش = NULL.
  4. (4) NOT EXISTS تختبر غياب الصف المطابق؛ NULL في Orders.UserId مش بتسمم كل النتيجة زي NOT IN.

إزالة التكرار بتعامل NULLs كـ not distinct عن بعضها، رغم إن NULL = NULL مش TRUE. ماتستنتجش سلوك set operators من مقارنة WHERE بس.

#Functional dependencies و Closure و KeysBonusFunctional dependencies, closure and keys

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

افترض جدول فيه سطر لكل منتج داخل order. ممكن OrderId واحد يظهر في كذا سطر، لكن كل السطور دي تخص نفس المستخدم. لو كل OrderId له UserId واحد مسموح به، نكتب OrderId → UserId. دي functional dependency، يعني قاعدة ثابتة في شكل الداتا: أي صفين متفقين على الشمال لازم يتفقوا على اليمين في كل حالة مسموحة، مش بس في العينة اللي قدامنا. السهم مش معناه العكس ولا علاقة سبب ونتيجة. هنستخدم القواعد دي نعرف إيه الأعمدة اللي تميّز order line واحدة.

OrderIdUserIdUserEmailProductIdQty
71a@example.test102
71a@example.test201

قبل الحساب: closure لمجموعة أعمدة هي كل الأعمدة اللي نقدر نستنتجها منها بتطبيق القواعد مراراً. لو الـ closure وصلت لكل أعمدة الجدول، فالمجموعة دي وبتعرّف الصف؛ ولو مافيش جزء أصغر منها يحقق ده تبقى candidate key. المفتاح الأساسي هو candidate key اختاره تصميم الجدول.

R(OrderId, UserId, UserEmail, ProductId, Qty)
Assumed rules: one line per product per order.
FDs:
  OrderId → UserId
  UserId → UserEmail
  OrderId, ProductId → Qty

{OrderId}+ = {OrderId, UserId, UserEmail}                    (1)
{OrderId, ProductId}+ = all attributes of R                 (2)
🧾 شرح الكود
  1. (1) Closure تبدأ بالصفات المعطاة، وتضيف اللي تقدر تستنتجه من لحد مفيش جديد.
  2. (2) الزوج بيوصل لكل الأعمدة، فهو superkey. إزالة أي جزء تمنع الوصول للكل، فهو candidate key كمان حسب القواعد المفترضة.

Superkey يحدد الصف؛ candidate key superkey minimal من غير attributes زيادة؛ primary key واحد اخترناه من المرشحين. Minimal مش معناه أقصر key بين كل المرشحين. ماافترضناش إن email فريد؛ لو القاعدة دي موجودة، أضفها وحلل من جديد.

CREATE TABLE OrderLines (
    OrderId int NOT NULL,
    ProductId int NOT NULL,
    Qty int NOT NULL,
    PRIMARY KEY (OrderId, ProductId)
);

الـ primary key بتنّفذ قاعدة الزوج الفريد، مش بتثبت باقي الـ FDs تلقائيًا.

#Normalization من الـ FDs وفرق Calculus عن AlgebraBonusNormalization from FDs, and calculus versus algebra

اختياري بس بيفرق: مش هيتسأل فيه في كل انترفيو، بس معرفته بتعمّق فهمك وبتميّزك عن غيرك.

تكرار UserEmail على كل سطر طلب بيعمل update anomalies: تعدل سطر وتنسى سطر. نفك الـ relation بناءً على dependencies، مش لمجرد إن الجدول كبير.

Formالاختبارتطبيق المثال
قيمة واحدة من domain لكل attribute؛ مفيش repeating groupsسطر لكل product بدل Product1 وProduct2
1NF ومفيش non-prime attribute معتمد على جزء حقيقي من أي candidate keyانقل UserId وUserEmail من سطور الطلب لأن OrderId لوحده يحددهم
لكل غير trivial: الشمال أو كل attribute على اليمين primeUserId → UserEmail محتاجة Users منفصلة هنا
الشمال superkey في كل FD غير trivialأقوى من 3NF؛ التحليل حسب كل الـ FDs

Prime يعني attribute داخلة في أي candidate key. لو فيه key واحدة بسيطة، وصف «مفيش transitive dependency لغير الـ key» مفيد، لكن مش بديل لتعريف 3NF العام.

Users(UserId PK, UserEmail)                              (1)
Orders(OrderId PK, UserId FK)
OrderLines(OrderId FK, ProductId, Qty, PK(OrderId, ProductId))

Lossless reconstruction:
Users ⋈ Orders ⋈ OrderLines                              (2)
SELECT O.OrderId, U.UserId, U.UserEmail, L.ProductId, L.Qty
FROM Orders O JOIN Users U ON U.UserId = O.UserId
JOIN OrderLines L ON L.OrderId = O.OrderId;               -- (3)
🧾 شرح الكود
  1. (1) كل حقيقة موجودة في مكان واضح حسب الـ FDs المفترضة.
  2. (2) Lossless معناها إعادة بناء الأصل من غير صفوف وهمية. عايزين dependency preservation كمان عشان القيود تتفحص محليًا؛ BCNF decomposition مش دايمًا تحفظ كل dependencies.
  3. (3) تعيد الصفوف الأصلية مع keys وforeign keys سليمة؛ مش كل تفكيك عشوائي يضمن ده.

Relational calculus بتحدد الصفوف المطلوبة بمنطق predicates وquantifiers؛ algebra بتعبّر عن تركيب operators. Safe، domain-independent calculus والـ classical algebra متكافئين في القدرة التعبيرية. SQL declarative وقريبة من المنطق ده، لكن bags و وaggregation إضافات لازم تتحسب. ده مش معناه إن algebra خطة physical بتفرض ترتيب التنفيذ.

ماتعملش denormalization قبل قياس bottleneck وتحديد مين يحدث النسخ. مرجع إضافي: Relational algebra and normalization.

أسئلة الانترفيو

راجع فهمك

ليه الاختيار ده مناسب؟ إمتى ممكن ماينفعش؟ وإيه اللي هيتغير لو الحمل زاد أو ظهر فشل؟

13.1Why would a .NET developer learn relational algebra?Junior

عشان تراجع معنى و: التكرار، صفوف بتضيع في join، وفلتر بيغير المعنى. مفيدة خصوصًا وإنت بتراجع query مولّدة من .

الإجابة النموذجية (English)

I use relational algebra as a compact reasoning tool for queries, not as notation I must write every day. It helps me ask which rows survive, which columns remain and whether a join multiplies rows. That is useful when reviewing -generated or an -generated report that looks plausible but returns wrong totals. I separate logical correctness from physical execution, then inspect the database plan to understand performance rather than assuming the written SQL determines execution order.

13.2What are a relation, tuple, attribute and domain?Junior

Relation مجموعة صفوف بنفس ، tuple صف، attribute عمود مسمى، domain القيم المسموحة. النظرية sets من غير ترتيب؛ ممكن bags و.

الإجابة النموذجية (English)

A relation is a set of tuples with a common . A tuple is one row, an attribute is a named component of that row, and its domain defines allowed values. In the classical model, a relation has neither duplicate tuples nor an inherent row order. I distinguish that from a table or query result, which can contain duplicates and NULLs. That distinction prevents me from translating theoretical set rules into SQL without checking their assumptions.

13.3How do selection, projection and rename map to SQL?Junior

σ تقابل WHERE، وπ تقابل SELECT DISTINCT للأعمدة المختارة، وρ تقابل aliases. كلمة SELECT في مش selection الجبرية.

الإجابة النموذجية (English)

Selection filters rows and usually maps to WHERE. selects attributes and, in set algebra, removes duplicates, so SELECT DISTINCT is the closer equivalent. Rename changes relation or attribute names and maps to table and column aliases. I point out the naming trap: SQL SELECT is mostly about projection, while algebraic selection means filtering. I also retain any attributes needed by later joins or predicates instead of projecting them away too early.

13.4What is the difference between UNION and UNION ALL?Junior

UNION بتشيل التكرار. UNION ALL تحتفظ بيه. لازم نفس عدد الأعمدة وأنواع متوافقة؛ مش join بتضيف أعمدة.

الإجابة النموذجية (English)

UNION combines compatible result sets and removes duplicate rows. UNION ALL keeps every occurrence, so it better expresses concatenation when duplicates are meaningful and avoids unnecessary deduplication. Both require the same column count and compatible types. I choose based on the intended result rather than using UNION to hide duplicate-producing joins. Neither operation implies row ordering, so I add a final ORDER BY when the consumer requires a stable presentation order.

13.5How are Cartesian product, theta join and equi-join related?Mid

× كل الأزواج. Theta هي filter على الأزواج بشرط عام. Equi شرطها مساواة. مهمة عشان متجمعش مبلغ متكرر بعد one-to-many join.

الإجابة النموذجية (English)

A Cartesian product forms every pair of input tuples. A theta join can be expressed as a selection over that product using a predicate, such as a price comparison. An equi-join is the special case using equality. I use this model to reason about : joining one order to several lines repeats the order's columns. Summing its total after that join can overcount even though the join predicate itself is perfectly valid.

13.6Why can a natural join be fragile?Mid

بتساوي كل الأعمدة المشتركة في الاسم تلقائيًا. إضافة Status للجدولين ممكن تضيف شرط ماكنتش تقصده. explicit ON أوضح و Server مافيهوش NATURAL JOIN.

الإجابة النموذجية (English)

A natural join automatically matches every same-named attribute and returns one copy of each shared attribute. That is concise in algebra but fragile in evolving schemas: adding a Status column to both tables can introduce a new equality condition and change the result without changing the query. I normally prefer explicit join predicates and an explicit . I also check dialect support, because Server does not provide NATURAL JOIN syntax.

13.7When would you use a semi-join instead of an inner join?Mid

لو عايز users اللي ليهم orders، مش عايز أعمدة orders ولا user يتكرر. EXISTS تمثل semi-join. NOT EXISTS للـ anti-join.

الإجابة النموذجية (English)

I use a semi-join when the question is whether a matching row exists, not which matching rows exist. For users who have orders, WHERE EXISTS returns each input user without multiplying it by the number of orders. An inner join followed by DISTINCT may express the same set, but it obscures the existence requirement. For users without orders, I use NOT EXISTS, checking the correlation predicate carefully and avoiding NOT IN when nullable values could change its meaning.

13.8How can a WHERE clause accidentally change a left join?Mid

الصف غير المطابق فيه O.Status بـ . WHERE O.Status = Paid ترجع فتشيله. حط الشرط في ON لو عايز كل users حتى اللي مالهمش paid order.

الإجابة النموذجية (English)

A left join preserves unmatched left rows by filling right-side attributes with . If I then put a right-side condition such as Order.Status equals Paid in WHERE, those NULL-extended rows fail the filter and disappear. If I want every user with any matching paid orders, I put that condition in ON. If I only want users who have paid orders, an inner join or EXISTS may describe the intention more clearly. I verify both matched and unmatched examples.

13.9What does relational division express?Mid

«كل» مش «أي»: users اللي اشتروا كل required products. Double NOT EXISTS معناها مفيش required product ناقصة. اختبر required set فاضية وحدد المرشحين.

الإجابة النموذجية (English)

Division expresses a for-every requirement, such as users who bought every required product. I often translate it into double NOT EXISTS: there is no required product for which the user has no purchase. I explicitly define the candidate universe and test the empty required set, because every candidate then qualifies by vacuous truth. A GROUP BY and HAVING alternative can work, but I must handle duplicates and missing candidates correctly instead of comparing raw row counts blindly.

13.10Why is SELECT DISTINCT not always a fix for duplicate rows?Mid

ممكن تشيل صفوف مختلفة في المعنى، أو تخبي join غلط. ولو SUM اتعملت قبلها، الرقم المكرر مش هيتصلح. راجع والـ keys.

الإجابة النموذجية (English)

I first determine whether repeated rows are legitimate bag semantics or a join error. DISTINCT can remove meaningful occurrences and can hide a missing join predicate. It also cannot repair an already inflated by a one-to-many join. I check keys, relationship and the level at which aggregation happens. Sometimes the right solution is EXISTS or aggregating the many-side first. I only add DISTINCT when unique projected tuples are actually the required result.

13.11How does NULL affect NOT IN and COUNT?Mid

مقارنة بـ بتطلع . NOT IN فيها NULL ممكن تستبعد كل unmatched values. COUNT(*) تعد كل الصفوف وCOUNT(column) تتجاهل NULL.

الإجابة النموذجية (English)

Comparisons with generally produce , and WHERE keeps only TRUE. If a NOT IN subquery contains NULL, an otherwise unmatched value can evaluate to UNKNOWN and disappear, which is why I often use a correlated NOT EXISTS. COUNT(*) counts rows, including rows containing NULLs, while COUNT(column) counts non-NULL values of that expression. I test nullable inputs explicitly because ordinary two-valued Boolean intuition is not sufficient for predicates.

13.12When is selection pushdown valid, and when is it dangerous?Senior

Filter على R بس ينزل تحت inner join. لكن outer join و وLIMIT وaggregates محتاجين تحليل. Equivalence منطقية مش وعد إن physical plan أسرع.

الإجابة النموذجية (English)

I can push a predicate referencing only one input below an inner join while preserving the result under the relevant semantics. That may reduce intermediate rows, but the physical benefit still depends on statistics and access paths. I do not apply the rule blindly to outer joins, aggregation, limits or nondeterministic expressions. I also preserve attributes needed by later predicates. The optimizer may already perform the rewrite, so I compare actual plans instead of assuming a nested subquery forces better execution.

13.13How do you compute attribute closure and identify candidate keys?Senior

ابدأ بالattributes، وطبق لحد الثبات. لو closure كل تبقى . لو مفيش attribute تنفع تتشال وتفضل superkey تبقى candidate.

الإجابة النموذجية (English)

I start the closure with the proposed attributes, then repeatedly apply functional dependencies whose left sides are already included, adding their right sides until nothing changes. If the closure covers the entire , the proposed set is a . I remove attributes to test minimality; a minimal superkey is a candidate key. I derive dependencies from business rules, not just sample data, and choose a primary key from the candidates after considering stability and implementation needs.

13.14How do functional dependencies lead to normalization?Senior

Partial dependency تكسر ، و determinant مش ويمين non-prime تكسر . فكك مع lossless join وراجع dependency preservation؛ أقوى ومش دايمًا تحفظ كل القيود محليًا.

الإجابة النموذجية (English)

I derive keys and dependencies first. A non-prime attribute depending on part of a candidate key violates . For , each nontrivial dependency must have a determinant or prime attributes on the right; requires the determinant to be a superkey. I decompose to remove update anomalies while checking lossless reconstruction and dependency preservation. Those are separate goals, and BCNF decomposition may sacrifice preservation. I only denormalize later for a measured workload with an explicit consistency strategy.

13.15How does relational calculus differ from relational algebra?Senior

Calculus تصف المطلوب بـ predicates وquantifiers. Algebra تركب operators. Safe domain-independent calculus والجبر الكلاسيكي متكافئين؛ فيها إضافات زي bags و.

الإجابة النموذجية (English)

Relational calculus describes which tuples satisfy a logical condition, using predicates and quantifiers. Relational algebra describes a composition of operations producing a relation. Safe, domain-independent calculus and classical algebra have equivalent expressive power, so they are alternative ways to describe the same class of relational queries. I would not confuse algebra with a fixed physical plan. adds practical semantics such as duplicates, and aggregation, which need separate treatment when translating theoretical equivalences.

اختبر نفسك

إجابات الاختبار وعلامات إكمال المحاور بتتحفظ على المتصفح ده، ومش بتتنقل لأجهزة تانية.

النتيجة: 0 / 0

Which operator filters tuples by a predicate?

σ للصفوف وπ للأعمدة.

Products has categories Books, Books, Office. What does π Category return under set semantics?

النظرية بتشيل التكرار.

R contains 3 tuples and S contains 4. How many tuples are in R × S?

كل صف من R بيتجمع مع كل صف من S.

Which SQL form naturally expresses users having at least one order without multiplying users?

دي semi-join، اختبار وجود بس.

What does relational division usually express?

÷ تستخدم شرط لكل عنصر مطلوب.

What does WHERE keep when a predicate evaluates to UNKNOWN?

FALSE و الاتنين بيستبعدوا الصف.

Which is required before pushing a predicate below an inner join onto R?

لازم الفلتر يبقى قابل للحساب من R وحدها.

A superkey with no removable attribute is called what?

Minimal هي candidate key.

Given A → B and B → C, which attributes are in {A}+?

نبدأ بـ A ونطبق السهمين بالتتابع.

What does a lossless decomposition guarantee?

Lossless reconstruction وdependency preservation ضمانين مختلفين.