Menu

Self Join ב-SQLite: שאילתה של טבלה מול עצמה

איך self join עובד ב-SQLite: התאמת שורות מאותה טבלה בעזרת כינויים, עם דוגמאות מעשיות של עובד ומנהל ושל נתונים היררכיים.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

Self join הוא פשוט JOIN עם כינויים

אין שום דבר מיוחד ב-self join. זה JOIN רגיל ששני הצדדים שלו הם במקרה אותה טבלה. הטריק הוא ש-SQLite צריכה דרך להבחין בין שני העותקים, ולכן נותנים לכל אחד כינוי.

משתמשים בו בכל פעם ששורה בטבלה מפנה לשורה אחרת באותה טבלה. המקרה הקלאסי: טבלת employees שבה לכל שורה יש manager_id שמצביע על עובד אחר:

ל-Ada אין מנהל. Boris ו-Cleo כפופים ל-Ada. Diego ו-Esme כפופים ל-Boris. היחס חי כולו בתוך טבלה אחת, ובדיוק שם self join מצדיק את עצמו.

הצורה הבסיסית

כדי לקבל כל עובד לצד השם של המנהל שלו, חברו את employees לעצמה. עותק אחד משחק את התפקיד של "עובד", והשני משחק "מנהל":

קראו את זה כשתי טבלאות שבמקרה חולקות אחסון. e היא שורת העובד, ו-m היא שורת המנהל. תנאי ה-JOIN e.manager_id = m.id מיישר אותן: לכל עובד, מצאו את השורה ב-m שה-id שלה מתאים ל-manager_id של העובד.

שימו לב ש-Ada לא הופיעה. ה-manager_id שלה הוא NULL, ו-INNER JOIN משמיט שורות שאין להן התאמה.

לשמור את השורות בלי התאמה: LEFT JOIN

אם אתם רוצים את כולם בתוצאה, כולל האנשים בלי מנהל, עברו ל-LEFT JOIN:

עכשיו Ada מופיעה עם NULL בעמודת המנהל. אותו מנגנון של self join, רק שסוג ה-JOIN עושה את מה ש-LEFT JOIN תמיד עושה: שומר כל שורה מהטבלה הראשונה (הצד השמאלי של ה-JOIN) וממלא ריקים כשאין התאמה.

זו הצורה שבדרך כלל רוצים כשמציגים רשימת אנשים. "אין מנהל" הוא מידע, ולהשמיט את השורה זה לא.

הכינויים אינם אופציונליים

נסו את ה-JOIN בלי כינויים, ול-SQLite אין מושג למה התכוונתם:

SELECT name, manager_id FROM employees JOIN employees ON manager_id = id;
-- Error: ambiguous column name: name

כל עמודה מופיעה פעמיים, פעם מכל עותק של הטבלה, ו-SQLite לא יכולה לבחור. כינויים פותרים את זה כשהם נותנים לכל מופע שם משלו. בחרו כינויים שמתארים את התפקיד שהשורה ממלאת, לא את הטבלה:

  • e ו-m לעובד ולמנהל.
  • parent ו-child להיררכיות.
  • a ו-b כשמשווים זוגות שרירותיים.

הכינוי הוא כל הסיבה ש-self join נקרא בצורה נקייה.

מציאת זוגות בתוך טבלה

Self join לא נועד רק להיררכיות. בכל פעם שרוצים להשוות שורות באותה טבלה, הדפוס מתאים. הנה רשימת מוצרים, ואנחנו רוצים כל זוג שהמחיר שלו זהה:

שני דברים לשים לב אליהם. ראשית, a.price = b.price הוא תנאי ההתאמה בפועל. שנית, a.id < b.id הוא מה שמונע מהשאילתה להחזיר כל זוג פעמיים (פעם כ-(Mug, Notebook) ופעם כ-(Notebook, Mug)) ולזווג כל שורה עם עצמה. כדאי לזכור את הטריק של <: הוא מופיע בכל פעם שמפרטים זוגות.

לעלות שתי רמות

Self join מטפל בקפיצה אחת בהיררכיה. רוצים את המנהל של המנהל של כל עובד? חברו שלוש פעמים:

כל כינוי חדש מייצג עוד רמה אחת למעלה בעץ. זה עובד היטב לשתיים או שלוש קפיצות, אבל מתפרק מהר: צריך לדעת את עומק ההיררכיה בזמן כתיבת השאילתה, ולהוסיף JOIN לכל רמה. זה הקיר ש-CTE רקורסיבי הומצא כדי לפרוץ.

מתי לא להשתמש ב-self join

Self join הוא הכלי הנכון כשצריך בתוצאה עמודות משני הצדדים של היחס. אם צריך רק לסנן, למשל למצוא כל עובד שהמנהל שלו הוא Ada, תת-שאילתה נקראת לעתים קרובות טוב יותר:

בלי התעמלות של כינויים, והכוונה ברורה לגמרי. כלל האצבע: אתם רוצים נתונים משתי השורות בפלט? Self join. אתם רק צריכים ערך להשוות אליו? תת-שאילתה.

להיררכיות בעומק שרירותי (תרשימים ארגוניים, עצי קבצים, תגובות בשרשור) אף אחד מהדפוסים לא מתאים לגדילה. זה התחום של CTE רקורסיבי.

הבא: תת-שאילתות

Self join ותת-שאילתות פותרים בעיות חופפות, ולדעת איזה מהם מתאים חוסך הרבה פזילה ל-SQL בהמשך. העמוד הבא מעמיק בתת-שאילתות, בצורות הסקלרית, המתואמת וה-IN, ובמקום שבו כל אחת מהן מצטיינת.

שאלות נפוצות

מה זה self join ב-SQLite?

Self join הוא JOIN רגיל שבו טבלה מחוברת לעצמה. נותנים לאותה טבלה שני כינויים שונים כדי ש-SQLite תוכל להתייחס אליהם כשני מקורות שורות נפרדים, ואז מתאימים שורות לפי עמודה שמקשרת שורה אחת לאחרת, לרוב יחס של הורה וילד כמו עובד ומנהל.

למה צריך כינויים ב-self join?

בלי כינויים, SQLite לא יכולה לדעת לאיזה עותק של הטבלה אתם מתכוונים כשאתם כותבים שם עמודה. מתן כינוי משלו לכל מופע (כמו e לעובד ו-m למנהל) מאפשר לכתוב e.manager_id = m.id בלי דו-משמעות. הכינויים אינם אופציונליים: השאילתה לא תעבור ניתוח בלעדיהם.

מתי כדאי להשתמש ב-self join ומתי בתת-שאילתה?

השתמשו ב-self join כשאתם רוצים עמודות משתי השורות בתוצאה, למשל את שם העובד וגם את שם המנהל באותה שורה. השתמשו בתת-שאילתה כשצריך רק לסנן או לחפש ערך בודד. להיררכיות בעומק רב אף אחד מהם לא מתאים: CTE רקורסיבי הוא הכלי הנכון.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל