Menu

טיפוסי נתונים ב-SQLite: מחלקות אחסון וטיפוסיות דינמית

איך SQLite שומרת ערכים: חמש מחלקות האחסון, למה הטיפוסיות דינמית, והמלכודות שתופסות את מי שמגיע מ-Postgres או מ-MySQL.

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

חמש מחלקות אחסון, לא הרבה טיפוסים

SQLite שומרת כל ערך כאחת מחמש מחלקות אחסון:

  • NULL: היעדר ערך.
  • INTEGER: מספר שלם עם סימן, בין 1 ל-8 בייטים לפי הגודל.
  • REAL: מספר נקודה צפה של 8 בייטים לפי IEEE.
  • TEXT: מחרוזת, שנשמרת בקידוד של מסד הנתונים (בדרך כלל UTF-8).
  • BLOB: בייטים גולמיים, שנשמרים בדיוק כפי שסיפקתם אותם.

זהו. אין BOOLEAN נפרד, אין DATETIME, אין VARCHAR, אין DECIMAL. למסדי נתונים אחרים יש עשרות טיפוסים; ל-SQLite יש חמישה, וכל השאר בנוי מעליהם.

typeof() מדווחת על מחלקת האחסון האמיתית של כל ערך. תראו integer, real, text, blob. ארבעת אלה, ועוד null, הם כל מה ש-SQLite מכירה.

הטיפוסיות דינמית

הנה החלק שמפתיע את מי שמגיע מ-Postgres או מ-MySQL. ב-SQLite (בלי STRICT), הטיפוס שמצהירים עליו בעמודה הוא יותר הצעה מאשר חוזה. הטיפוס האמיתי חי עם כל ערך:

שתי השורות התקבלו. העמודה id מחזיקה מספר שלם בשורה אחת וטקסט בשנייה; body מחזיקה טקסט ומספר שלם. SQLite שומרת בשמחה ערכים מכל מחלקה בכל עמודה.

זו טיפוסיות דינמית, וזו בחירת תכנון מכוונת. היא הופכת את SQLite לסלחנית לאבות טיפוס ולסקריפטים מהירים. היא גם אומרת ששגיאת הקלדה בקוד של האפליקציה יכולה לשמור בשקט נתונים בצורה הלא נכונה במשך שנים. אם הפשרה הזו מטרידה אתכם, וברוב הסכמות בפרודקשן היא צריכה להטריד, טבלאות STRICT הן התשובה. נגיע אליהן בקרוב.

Type Affinity בפסקה אחת

הטיפוס המוצהר של עמודה לא מתעלמים ממנו; הוא נותן לעמודה affinity (זיקה לטיפוס). כשמכניסים ערך, SQLite מנסה להמיר אותו לכיוון ה-affinity של העמודה אם יש המרה נקייה. עמודת TEXT שמקבלת את המספר 42 שומרת אותו כטקסט '42'; עמודת INTEGER שמקבלת את המחרוזת '42' שומרת אותה כמספר שלם 42. אם ההמרה הייתה מאבדת מידע, הטיפוס המקורי נשמר.

שורה ראשונה: המספר השלם 42 הומר לטקסט '42', והמחרוזת '100' הומרה למספר השלם 100. שורה שנייה: '3.5' לא יכול היה לעבור ל-INTEGER בלי אובדן, ולכן נשאר טקסט. ל-affinity יש עמוד משלו בהמשך; בינתיים, רק דעו שטיפוס העמודה עדיין משפיע על האחסון, גם אם הוא לא אוכף אותו.

ערכים בוליאניים

אין מחלקת אחסון BOOLEAN. SQLite שומרת ערכים בוליאניים כמספרים שלמים: 0 לשקר, 1 לאמת:

מילות המפתח TRUE ו-FALSE מזוהות (מאז SQLite 3.23) ומתורגמות ל-1 ול-0. ההצהרה BOOLEAN נותנת לעמודה affinity מספרי אבל לא מגבילה אותה ל-0/1: בלי STRICT, הייתם יכולים להכניס 'maybe' ו-SQLite לא הייתה מתנגדת.

תאריכים ושעות

גם DATETIME אין. בוחרים אחד משלושה קידודים, ופונקציות התאריך של SQLite עובדות על כולם:

  • TEXT בפורמט ISO-8601: '2026-04-23 14:30:00'.
  • REAL כמספרי יום יוליאני.
  • INTEGER כשניות מאז Unix epoch.

טקסט ב-ISO-8601 הוא הבחירה הנפוצה ביותר: הוא ממוין נכון כמחרוזת, קריא לבני אדם, והפונקציות המובנות (date(), time(), datetime(), strftime(), julianday()) כולן מקבלות אותו. בחרו קידוד אחד לכל עמודה והישארו איתו; ערבוב פורמטים בתוך עמודה אחת הוא בדיוק מסוג הדברים שנושכים אתכם חצי שנה אחר כך.

VARCHAR, CHAR ושמות מוכרים אחרים

SQLite מקבלת את שמות הטיפוסים שאתם מכירים ממסדי נתונים אחרים: VARCHAR(255), CHAR(10), NVARCHAR, DECIMAL(10,2), DOUBLE, FLOAT, INT, BIGINT, MEDIUMINT. כולם מפוענחים בלי בעיה. הם פשוט ממופים לאחת מחמש מחלקות האחסון לפי כללי ה-affinity.

VARCHAR(255) לא אוכף מגבלה של 255 תווים: SQLite מתעלמת מהאורך. DECIMAL(10, 2) לא שומר מספר עשרוני בדיוק קבוע: הוא מקבל affinity מספרי ונשמר כ-INTEGER או כ-REAL. השמות קיימים רק כדי שסכמות שהועתקו ממסדי נתונים אחרים ירוצו; הם לא מביאים איתם את האילוצים שהשמות האלה מרמזים עליהם במקומות אחרים.

אם אתם צריכים חשבון עשרוני מדויק לכסף, שמרו אגורות כ-INTEGER. REAL בנקודה צפה יכניס במוקדם או במאוחר שגיאות עיגול בספרה השלישית אחרי הנקודה.

NULL הוא מחלקת אחסון

NULL הוא לא רק "אין ערך": זה ערך עם מחלקת אחסון משלו, ש-typeof() מחזירה:

b מדווח כ-null. זה חשוב כי NULL לא שווה לשום דבר, אפילו לא ל-NULL אחר. b = NULL אף פעם לא אמת; צריך לכתוב b IS NULL. הנושא יעלה כמו שצריך בעמוד על אופרטורים ו-NULL בהמשך, אבל הוא מתחיל כאן, עם מחלקת האחסון.

שמירת בייטים עם BLOB

BLOB שומר בייטים גולמיים כמו שהם: שימושי לתמונות קטנות, hashes, נתונים מקודדים, כל דבר שאינו טקסט או מספר:

הערך המילולי x'...' מאפשר לכתוב blobs בהקסדצימלי ב-SQL; מקוד של אפליקציה, בדרך כלל מעבירים מערך בייטים דרך פרמטר. length() על blob מחזירה את מספר הבייטים, לא את מספר התווים.

הערה מעשית: SQLite שומרת בשמחה blobs גדולים, אבל למשוך blob של 50 MB בכל שאילתה שנוגעת בשורה זה איטי. לקבצים גדולים, שמרו את הקובץ בדיסק והחזיקו נתיב במסד הנתונים.

מה לקחת מכאן

  • חמש מחלקות אחסון, NULL, INTEGER, REAL, TEXT, BLOB, מכסות הכול.
  • ערכים בוליאניים הם מספרים שלמים; תאריכים הם טקסט, real או integer (לבחירתכם).
  • טיפוסי עמודות מוצהרים הם רמזים, לא חוזים (אלא אם משתמשים ב-STRICT).
  • VARCHAR(255) וחבריו מפוענחים, אבל לא אוכפים את האורך או הדיוק שהם מרמזים עליהם במקומות אחרים.
  • typeof(value) הוא החבר שלכם בכל פעם שאתם לא בטוחים מה באמת נשמר.

הבא בתור: Type Affinity

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

שאלות נפוצות

באילו טיפוסי נתונים SQLite תומכת?

ל-SQLite יש חמש מחלקות אחסון: NULL, INTEGER, REAL, TEXT ו-BLOB. כל ערך במסד הנתונים נשמר כאחת מהן. השמות המוכרים כמו VARCHAR(255), DATETIME או BOOLEAN מתקבלים ב-CREATE TABLE לצורך תאימות, אבל בזמן האחסון הם ממופים לאחת מהחמש.

יש ל-SQLite טיפוס בוליאני או טיפוס של תאריך ושעה?

לא כמחלקות אחסון נפרדות. ערכים בוליאניים נשמרים כ-INTEGER (0 ו-1), אם כי SQLite מזהה גם את מילות המפתח TRUE ו-FALSE. תאריכים ושעות נשמרים כ-TEXT (מחרוזות ISO-8601), כ-REAL (מספרי יום יוליאני) או כ-INTEGER (שניות מאז Unix epoch): אתם בוחרים את הקידוד, ופונקציות התאריך עובדות על שלושתם.

למה הטיפוסיות ב-SQLite נקראת דינמית?

ברוב מסדי הנתונים, עמודה שהוגדרה INTEGER דוחה מחרוזות. ב-SQLite (כברירת מחדל), הטיפוס המוצהר הוא רמז: הטיפוס האמיתי נוסע עם כל ערך, כך שעמודת TEXT יכולה להחזיק מספר שלם אם הכנסתם כזה. הגמישות הזו שימושית לפעמים ומסוכנת לפעמים. טבלאות STRICT מכבות אותה.

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

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

להתחיל