Menu

Type Affinity ב-SQLite: איך טיפוסי עמודות מתנהגים באמת

איך מערכת ה-type affinity של SQLite עובדת: חמשת סוגי ה-affinity, הכללים שבוחרים אחד מהם לפי הגדרת העמודה, ולמה עמודת INTEGER יכולה להכיל מחרוזת.

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

Affinity הוא העדפה, לא כלל

SQLite הוא בעל טיפוסיות דינמית. ערך נושא איתו את סוג האחסון שלו (NULL, INTEGER, REAL, TEXT, BLOB), והטיפוס שהוגדר לעמודה לא מגביל באופן קשיח מה אפשר להכניס אליה. מה שהטיפוס המוגדר כן עושה הוא לתת לעמודה affinity: סוג אחסון מועדף ש-SQLite מנסה להמיר אליו ערכים נכנסים.

שימו לב מה קורה כש-affinity לא מספיק כדי לעצור אי התאמה:

השורה השנייה שומרת את המחרוזת 'two' בעמודת INTEGER. SQLite ניסה להמיר את 'two' למספר, לא הצליח (זה לא מספרי), ושמר אותו בכל זאת כ-TEXT. typeof() חושף את סוג האחסון האמיתי של כל ערך, והוא לא תמיד מה שהגדרת העמודה מרמזת.

זה מפתיע אנשים שמגיעים מ-Postgres או מ-MySQL. זה בכוונה.

חמשת סוגי ה-Affinity

כל עמודה בטבלה שאינה STRICT מקבלת בדיוק אחד מאלה:

  • TEXT: מעדיף מחרוזות.
  • NUMERIC: מעדיף מספרים, אבל מקבל טקסט אם אי אפשר להמיר.
  • INTEGER: כמו NUMERIC, אבל שומר ערכים בלי חלק שברי כמספרים שלמים.
  • REAL: מעדיף מספרים עשרוניים (נקודה צפה).
  • BLOB: בלי העדפה, שומר כל מה שנותנים לו.

ל-affinity מסוג BLOB קוראים גם "ללא affinity": זה מה שמקבלים כשלא מגדירים טיפוס בכלל.

אותו קלט, המחרוזת '42', וחמישה טיפוסים שמורים שונים. כל עמודה המירה (או לא) לפי ה-affinity שלה.

איך SQLite בוחר Affinity מתוך ההגדרה שלכם

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

  1. מכיל INT → INTEGER
  2. מכיל CHAR, CLOB או TEXT → TEXT
  3. מכיל BLOB, או שאין טיפוס בכלל → BLOB
  4. מכיל REAL, FLOA או DOUB → REAL
  5. כל דבר אחר → NUMERIC

זה כל האלגוריתם. הוא מסביר הרבה מוזרויות:

FLOATING_POINTS הופך ל-INTEGER כי תת המחרוזת INT מופיעה ב-POINTS. הכלל הראשון שמתאים מנצח, מלמעלה למטה. זו הסיבה שהעתקה עיוורת של טיפוסים ממסד נתונים אחר יכולה לתת משהו שונה ממה שציפיתם.

Affinity בפעולה: המרות בזמן הכנסה

Affinity חשוב במיוחד כש-SQLite מחליט אם להמיר את הערך שלכם או לשמור אותו כמו שהוא. הכללים:

  • affinity מסוג TEXT: מספרים ו-BLOBים מומרים לטקסט.
  • affinity מסוג NUMERIC, INTEGER, REAL: טקסט שנראה כמו מספר מומר. טקסט שלא נראה כך נשאר טקסט.
  • affinity מסוג BLOB: שום דבר לא מומר.

שורה אחר שורה:

  • '123' בעמודת NUMERIC הופך למספר השלם 123. ההמרה מטקסט למספר הצליחה ולא איבדה מידע.
  • '12.5' הופך למספר העשרוני 12.5.
  • 'hello' ב-NUMERIC נשאר טקסט: אין מספר להמיר אליו.
  • עמודת ה-TEXT ממירה מספרים לצורת המחרוזת שלהם.
  • עמודת ה-BLOB שומרת הכול בדיוק כמו שניתן, כולל הטיפוס.

הקמט של INTEGER מול REAL

affinity מסוג INTEGER מתנהג כמעט זהה ל-NUMERIC, עם שינוי אחד: ערך כמו 3.0 שאין לו חלק שברי אמיתי נשמר כמספר השלם 3 כדי לחסוך מקום.

3.0 נוחת כ-INTEGER בשתי העמודות: האופטימיזציה קורית גם ב-NUMERIC. 3.5 שומר על החלק השברי ונשאר REAL. המסקנה: אל תסמכו על typeof() כדי לדעת אם עמודה הוגדרה INTEGER או REAL. הוא אומר מה באמת שמור, וזה יכול להשתנות משורה לשורה.

כש-Affinity נושך אתכם

הגמישות נוחה עד שהיא לא. שני סוגי כשלים מופיעים בקוד אמיתי:

1. נתונים גרועים מתגנבים פנימה. אם יש באפליקציה שלכם באג ששולח 'N/A' לעמודת INTEGER, SQLite ישמור אותו. שאילתות מאוחרות יותר שעושות חשבון על העמודה יחזירו תוצאות מוזרות או NULL. בלי שגיאה, בלי אזהרה, רק השחתה שקטה.

2. השוואות נהיות מוזרות. מיון ובדיקות שוויון מתייחסים אחרת לערכים מסוגי אחסון שונים:

מספרים שלמים ממוינים מספרית, ואז ערכי טקסט ממוינים לקסיקוגרפית, והם ממוינים אחרי כל המספרים. אז מקבלים 2, 3, 10 (המספרים השלמים בסדר מספרי), ואז '20', '100' (המחרוזות בסדר אלפביתי). לא מה שרוב האנשים רוצים.

אם אתם שולטים בהכנסות ומאמתים בקפידה, טבלאות רגילות הן בסדר. אם לא, או שאתם פשוט רוצים שמסד הנתונים יאכוף טיפוסים בשבילכם, יש אפשרות טובה יותר.

הבא בתור: טבלאות STRICT

SQLite 3.37 הוסיף טבלאות STRICT, שמכבות את ה-affinity ודוחות ערכים שלא תואמים לטיפוס המוגדר. הן נותנות את הטיפוסיות הדינמית כברירת מחדל כשאתם רוצים אותה, ואכיפה בסגנון Postgres כשלא. זה הדף הבא.

שאלות נפוצות

מה זה type affinity ב-SQLite?

Type affinity הוא סוג האחסון המועדף של עמודה. ל-SQLite יש חמישה: TEXT, NUMERIC, INTEGER, REAL ו-BLOB. כשמכניסים ערך, SQLite מנסה להמיר אותו ל-affinity של העמודה, אבל אם ההמרה תאבד מידע או בלתי אפשרית, הוא שומר את הערך כמו שהוא. Affinity הוא רמז, לא אילוץ קשיח.

איך SQLite מחליט מה ה-affinity של עמודה?

SQLite סורק את שם הטיפוס שכתבתם ב-CREATE TABLE ומחפש בו תת מחרוזות, לפי הסדר: אם הוא מכיל INT הוא INTEGER. אחרת, CHAR, CLOB או TEXT הופכים אותו ל-TEXT. אחרת, BLOB (או היעדר טיפוס) הופך אותו ל-BLOB. אחרת, REAL, FLOA או DOUB הופכים אותו ל-REAL. בכל מקרה אחר, NUMERIC. זו הסיבה ש-VARCHAR(50) הופך ל-TEXT ו-BIGINT הופך ל-INTEGER: המילים שאתם כותבים עוברות התאמת תבניות.

האם עמודה ב-SQLite יכולה להכיל ערכים מהטיפוס הלא נכון?

כן, בטבלאות רגילות. עמודה שהוגדרה INTEGER תשמור בשמחה את המחרוזת 'hello', כי affinity רק מציע המרה. אם אתם רוצים אכיפה קשיחה של טיפוסים, השתמשו בטבלאות STRICT, שדוחות ערכים לא תואמים על הסף. נכסה אותן בדף הבא.

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

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

להתחיל