DISTINCT מסיר שורות כפולות
כברירת מחדל, SELECT מחזיר כל שורה מתאימה, כולל כפילויות. DISTINCT אומר ל-SQLite לכווץ שורות שזהות בכל העמודות שבחרתם, כך שכל צירוף ייחודי מופיע רק פעם אחת.
חמש שורות נכנסות, שלוש יוצאות. SQLite הסתכלה על העמודה customer, זרקה את החזרות, והחזירה שורה אחת לכל ערך ייחודי. הסדר לא מובטח: הוסיפו ORDER BY אם הוא חשוב לכם.
DISTINCT חל על כל רשימת ה-SELECT
זה מפיל אנשים. DISTINCT לא בוחר עמודה אחת להסיר בה כפילויות; הוא מסיר שורות כפולות שלמות לפי כל העמודות שבחרתם.
כל זוג (customer, country) ייחודי מופיע פעם אחת. אם אותו לקוח היה מופיע עם שתי מדינות שונות, הייתם רואים את שתי השורות: מבחינת SQLite הן לא כפולות.
אין תחביר DISTINCT(customer) שמתעלם משאר העמודות. הסוגריים נראים מפתים, אבל SELECT DISTINCT(customer), country מפוענח בדיוק כמו SELECT DISTINCT customer, country: הסוגריים רק מקבצים ביטוי. אם אתם באמת רוצים שורה אחת לכל לקוח עם מדינה נבחרת כלשהי, זו עבודה ל-GROUP BY יחד עם פונקציית צבירה.
COUNT(DISTINCT col)
צורך נפוץ: כמה ערכים ייחודיים יש בעמודה? COUNT(*) סופר שורות, COUNT(col) סופר ערכים שאינם NULL, ו-COUNT(DISTINCT col) סופר ערכים ייחודיים שאינם NULL.
חמש הזמנות, שלושה לקוחות ייחודיים, שלוש מדינות ייחודיות. COUNT(DISTINCT ...) היא צורת הצבירה השימושית ביותר של DISTINCT: תשתמשו בה בכל פעם שתרצו לספור "כמה דברים שונים הופיעו".
שימו לב ש-SQLite מאפשרת רק עמודה אחת בתוך COUNT(DISTINCT ...). כדי לספור צירופים ייחודיים של כמה עמודות, עטפו אותן בתת שאילתה: SELECT COUNT(*) FROM (SELECT DISTINCT a, b FROM t).
איך DISTINCT מתייחס ל-NULL
ל-NULL יש מוניטין מוזר ב-SQL, כי NULL = NULL מחזיר NULL, לא TRUE. אבל DISTINCT עושה חריגה מיוחדת: לצורך הסרת כפילויות, כל ה-NULL נחשבים שווים זה לזה.
חוזרות שלוש שורות: 'ada@example.com', 'dan@example.com' ו-NULL יחיד. שלוש כתובות האימייל שהן NULL התכווצו לאחת. אותו כלל חל על GROUP BY ועל פעולות קבוצה כמו UNION: שימושי לזכור כשמחפשים את התשובה ל"למה שורת ה-NULL הזו מופיעה פעם אחת במקום שלוש?"
DISTINCT רץ לפני ORDER BY ו-LIMIT
לפסוקיות ב-SELECT יש סדר לוגי: FROM, ואז WHERE, ואז GROUP BY, ואז HAVING, ואז SELECT/DISTINCT, ואז ORDER BY, ולבסוף LIMIT. כך ש-DISTINCT מסנן כפילויות קודם, אחר כך ORDER BY ממיין את מה שנשאר, ואז LIMIT חותך.
WHERE משאיר ארבע שורות, DISTINCT מכווץ את הכפילויות של Boris, ORDER BY ממיין לפי סדר אלפביתי, LIMIT מחזיר את השתיים הראשונות. שווה לעקוב אחרי זה פעם אחת: בלבול לגבי סדר התוצאות נובע בדרך כלל משכחה של איזה שלב קורה מתי.
DISTINCT מול GROUP BY
להסרת כפילויות בלבד, שתי השאילתות האלה מחזירות את אותן שורות:
אותה תוצאה. ההבדל הוא מה אפשר לעשות אחר כך:
DISTINCTנועד ל"תנו לי שורות ייחודיות" ותו לא.GROUP BYנועד ל"חלקו שורות לדליים וחשבו משהו לכל דלי":COUNT(*),SUM(amount),MAX(created_at)וכן הלאה.
אם אתם מוצאים את עצמכם פונים ל-DISTINCT ואז מבינים שאתם רוצים גם סכום לכל לקוח, זה הסימן לעבור ל-GROUP BY:
שורה אחת לכל לקוח, עם הצבירות שרציתם. DISTINCT לא יכול לעשות את זה: אין לו דרך לבטא "שורה אחת לכל קבוצה ועוד סכום".
כמה דברים שכדאי לשים לב אליהם
- ביצועים.
DISTINCTדורש בדרך כלל ש-SQLite תמיין את השורות או תבצע עליהן hash כדי למצוא כפילויות. בתוצאות גדולות, אינדקס על העמודה או העמודות שבהן מסירים כפילויות עוזר. אם אתם עושיםSELECT DISTINCTעל כל העמודות של טבלה רחבה, שאלו את עצמכם אם אתם באמת צריכים כל עמודה. DISTINCT *נדיר. הוא חוקי,SELECT DISTINCT * FROM tמסיר שורות כפולות שלמות, אבל אם לטבלה יש מפתח ראשי, כל שורה כבר ייחודית, כך שזה לא עושה שום דבר מועיל.- אל תבלבלו עם
UNIQUE.UNIQUEהוא אילוץ על טבלה שמונע מלכתחילה הכנסה של ערכים כפולים.DISTINCTהוא מסנן בזמן השאילתה שמסתיר כפילויות בתוצאה. כלים שונים, תפקידים שונים.
הבא בתור: ביטויי CASE
ברגע שאתם יודעים לעצב שורות תוצאה עם SELECT, WHERE, ORDER BY ו-DISTINCT, הצעד הבא הוא לוגיקה מותנית בתוך שאילתה. ביטויי CASE מאפשרים להחזיר ערכים שונים לפי תנאים, המקבילה ב-SQL לסולם של if/else, והעמוד הבא מכסה אותם.
שאלות נפוצות
איך SELECT DISTINCT עובד ב-SQLite?
SELECT DISTINCT מסיר שורות כפולות מהתוצאה. SQLite משווה כל עמודה ברשימת ה-SELECT ומשאירה שורה אחת לכל צירוף ייחודי. הוא מוחל אחרי WHERE ו-JOIN אבל לפני ORDER BY ו-LIMIT.
אפשר להשתמש ב-DISTINCT על כמה עמודות ב-SQLite?
כן: DISTINCT חל תמיד על כל רשימת ה-SELECT, לא על עמודה אחת. SELECT DISTINCT city, country FROM users מחזיר כל זוג (city, country) ייחודי. אין תחביר DISTINCT(city) שמתעלם משאר העמודות; אם אתם צריכים את זה, השתמשו ב-GROUP BY עם פונקציית צבירה.
איך DISTINCT מטפל בערכי NULL ב-SQLite?
DISTINCT מתייחס ל-NULL כשווה ל-NULL אחרים לצורך הסרת כפילויות, כך שכמה שורות עם NULL מתכווצות לאחת. זה שונה מהאופן שבו = עובד בפסוקיות WHERE, שם NULL = NULL הוא לא ידוע. זה כלל מיוחד רק ל-DISTINCT, ל-GROUP BY ול-UNION.
מה ההבדל בין DISTINCT ל-GROUP BY ב-SQLite?
להסרת כפילויות בלבד, SELECT DISTINCT col ו-SELECT col FROM t GROUP BY col מפיקים תוצאות זהות. ההבדל הוא בכוונה: השתמשו ב-DISTINCT כשאתם רק רוצים שורות ייחודיות, וב-GROUP BY כשאתם רוצים גם לחשב צבירות כמו COUNT(*) או SUM(amount) לכל קבוצה.