הבלוג של גרי רשף

28/02/2011

פעולות חיתוך ואיחוד בין קבוצות וביצוע Union בעזרת Join

Filed under: Uncategorized — תגיות: , , , , , , , , , — גרי רשף @ 17:26

דרך מעניינת להסתכל על טבלאות היא כעל קבוצות של רשומות.
נכון שהדימוי האינטואיטיבי הוא דווקא של רשימה מסודרת (טבלה..) אבל לסדר אין חשיבות והטבלה נשארת אותה טבלה ללא קשר לאופן המיון הלוגי או הפיזי של הרשומות (זו כנראה אחת הסיבות להתעקשותה של Microsoft לא לאפשר ביצוע Order By ב-View), ובין טבלאות ניתן לבצע פעולות חיתוך ואיחוד כפי שלמדנו במבוא לתורת הקבוצות..

לצורך ההמחשה ניצור שתי טבלאות בעלות מבנה זהה, ונכניס לתוכן נתונים – חלקם זהים וחלקם שונים:

Use tempdb;

Go


If Object_Id('Tbl1') Is Not Null Drop Table Tbl1;

Go


Create Table Tbl1(ID Int Primary Key,

                Name Varchar(10),

                Date DateTime);

Go


Insert

Into Tbl1

Select 1,'Anat','19700101' Union All

Select 2,'Beni','19750201' Union All

Select 3,'Galit','19770301' Union All

Select 4,'Dana','19800401';

Go


If Object_Id('Tbl2') Is Not Null Drop Table Tbl2;

Go


Create Table Tbl2(ID Int Primary Key,

                Name Varchar(10),

                Date DateTime);

Go


Insert

Into Tbl2

Select 3,'Galit','19770301' Union All

Select 4,'Dana','19800401' Union All

Select 5,'Eli','19880501' Union All

Select 6,'Hila','19900601';

Go

clip_image002

חיתוך (השטח הכחול המשותף לשתי הטבלאות) מתקבל על ידי Join:

Select  *

From    Tbl1

Inner Join Tbl2

        On Tbl1.ID=Tbl2.ID;

Go

clip_image004

השטח של Tbl1 על ידי Left Join בינה לבין Tbl2 (ואפשר להבחין בפלט היכן החלק התכול והיכן הכחול):

Select  *

From    Tbl1

Left Join Tbl2

        On Tbl1.ID=Tbl2.ID;

Go

את החלק הכחול ללא התכול ניתן להציג על ידי הוספת תנאי Is Null על Tbl2.

clip_image006

השטח של Tbl2 על ידי Right Join:

Select  *

From    Tbl1

Right Join Tbl2

        On Tbl1.ID=Tbl2.ID;

Go

clip_image008

האיחוד יכול להתקבל בעזרת Full Join:

Select  *

From    Tbl1

Full Join Tbl2

        On Tbl1.ID=Tbl2.ID;

Go

את השטחים התכולים ללא החיתוך הכחול ניתן לקבל על ידי תנאי Is Null על כל אחת מהטבלאות, ויחס Or בינהם.

clip_image010

רגע, איחוד זה לא Union?

בוודאי- נכון שנהוג להציג את פעולת Join כ"טבלה ליד טבלה" (או שתי טבלאות במקביל) ואת פעולת Union כ"טבלה מעל טבלה" (או שתי טבלאות בטור) אבל הגמישות של ה-Join מאפשר הרבה יותר מהצפוי, כולל ביצוע Union.

נתחיל עם Union פשוט שמבצע גם Distinct ומפלטר רשומות כפולות:

Select  *

From    Tbl1

Union

Select  *

From    Tbl2;


Select  IsNull(Tbl1.ID,Tbl2.ID) ID,

        IsNull(Tbl1.Name,Tbl2.Name) Name,

        IsNull(Tbl1.Date,Tbl2.Date) Date

From    Tbl1

Full Join Tbl2

        On Tbl1.ID=Tbl2.ID;

Go

clip_image012

ונמשיך עם Union All שמציג את כל הרשומות, כולל כפילויות:

Select  *

From    Tbl1

Union All

Select  *

From    Tbl2;


Select  IsNull(Tbl1.ID,Tbl2.ID) ID,

        IsNull(Tbl1.Name,Tbl2.Name) Name,

        IsNull(Tbl1.Date,Tbl2.Date) Date

From    Tbl1

Full Join Tbl2

        On 1=2;

Go

clip_image014

במקרה זה צירפנו לאופרטור On תנאי שאף פעם אינו מתקיים (1=2) וכתוצאה מכך לא נוצרה אף התאמה (גם כשכן הייתה) וכל טבלה הוצגה בנפרד.

באופן דומה- גם את פעולת החיסור נוכל לבצע הן בעזרת Except הפשוט והאינטואיטיבי והן בעזרת Left Join ותנאי Is Null:

Select  *

From    Tbl1

Except

Select  *

From    Tbl2;


Select  Tbl1.*

From    Tbl1

Left Join Tbl2

        On Tbl1.ID=Tbl2.ID

Where   Tbl2.ID Is Null;

Go

clip_image016

כדאי אולי לצרף הסתייגות קטנה לפרוטוקול: כשיש Nulls ובעיקר כשיש השוואה בין Nulls מקבלים תוצאות לא תמיד צפויות, והיתרון של Union ו-Except שהם גם פשוטים מבחינת הסינטקס וההבנה האינטואיטיבית, וגם ידידותיים מבחינת התוצאות במקרה של Nulls.

Older Posts »

יצירה של אתר חינמי או בלוג ב־WordPress.com.