Menu

SQLite DISTINCT: הסרת כפילויות משאילתות SELECT

איך SELECT DISTINCT עובד ב-SQLite: עמודה אחת, כמה עמודות, טיפול ב-NULL, COUNT(DISTINCT), ומתי GROUP BY הוא הכלי הטוב יותר.

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

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) לכל קבוצה.

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

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

להתחיל