UPDATE משנה שורות קיימות
INSERT מוסיף שורות חדשות. UPDATE משנה שורות שכבר קיימות. הצורה קצרה ושווה לשנן אותה:
UPDATE table_name
SET column = value
WHERE condition;
דוגמה עובדת:
SET אומר מה משתנה. WHERE אומר אילו שורות. שאר הטבלה לא נפגעת.
פסוקית WHERE היא לא אופציונלית בפועל
מבחינה טכנית, WHERE אופציונלי. מבחינה מעשית, השמטה שלו היא הדרך שבה מהנדסים מתחילים הורסים לעצמם את אחר הצהריים:
UPDATE users SET status = 'inactive';
-- every single user is now inactive
בלי סינון, כל שורה מתאימה. SQLite ייענה בשקט. תמיד כתבו קודם את ה-WHERE, ואז את ה-SET: ההרגל הזה לבדו מונע הרבה תאונות.
אם אתם לא בטוחים שה-WHERE שלכם נכון, הריצו קודם את אותו תנאי כ-SELECT:
אותו תנאי, שתי פקודות. ה-SELECT הוא ההרצה היבשה שלכם.
עדכון כמה עמודות
הפרידו את ההשמות בפסיקים בתוך SET יחיד. SET אחד, עמודות רבות:
גישה אחת למסד הנתונים, שורה אחת משתנה, שלוש עמודות מתעדכנות. אל תכתבו שלוש פקודות UPDATE נפרדות כשאחת מספיקה.
ביטויים מימין ל-=
הערך שאחרי = לא חייב להיות ליטרל. הוא יכול להיות כל ביטוי, כולל כזה שמתייחס לערך הנוכחי של העמודה:
price * 1.10 קורא את המחיר הקיים, מכפיל, וכותב את התוצאה בחזרה. SQLite מחשב את הצד הימני לפי הערכים הנוכחיים של השורה לפני שאחת מההשמות של הפקודה הזו נכנסת לתוקף, כך שאפשר להתייחס לכמה עמודות בבטחה:
UPDATE products SET price = price * 1.10, stock = stock + price;
-- 'price' on the right side here is the OLD price, not the just-updated one.
UPDATE ... FROM: שליפת ערכים מטבלה אחרת
מאז SQLite 3.33, UPDATE תומך בפסוקית FROM לעדכונים בין טבלאות. זו הדרך הנקייה ביותר לסנכרן נתונים בין טבלאות:
תת השאילתה מחשבת סכומים לכל לקוח. ה-UPDATE החיצוני מצרף את התוצאות האלה בחזרה ל-customers לפי id. בלי UPDATE ... FROM הייתם כותבים תת שאילתה מתואמת לכל עמודה, וזה הרבה יותר רועש.
כמה כללים שכדאי לזכור:
- טבלת היעד באה אחרי
UPDATE, לא ברשימת ה-FROM. - פסוקית ה-
WHEREמבצעת את ה-join: אין כאן מילת מפתחON. - אם ה-join יכול להתאים ליותר משורה אחת ב-
FROM, התוצאה לא מוגדרת. ודאו שמפתחות ה-join מפיקים לכל היותר התאמה אחת לכל שורת יעד.
RETURNING: לראות מה השתנה
SQLite (3.35 ומעלה) מאפשר ל-UPDATE להחזיר את השורות ששונו באותה פקודה. נוח כשהאפליקציה צריכה את הערכים שאחרי העדכון בלי SELECT נוסף:
מקבלים בחזרה את השורות שבאמת נגעו בהן, עם הערכים החדשים שלהן. זה חוסך גישה נוספת ומבטל סוג שלם של תנאי מרוץ בקוד מקבילי. יש דף שלם על RETURNING בהמשך הפרק.
UPDATE OR REPLACE: טיפול בהתנגשויות אילוצים
אם העדכון שלכם יפר אילוץ UNIQUE, ברירת המחדל היא לבטל את הפקודה עם שגיאה. פסוקית ה-OR מאפשרת לבחור מדיניות אחרת:
האפשרויות הן OR ABORT (ברירת המחדל), OR REPLACE, OR IGNORE, OR FAIL ו-OR ROLLBACK. REPLACE היא המסוכנת: היא מוחקת את השורה המתנגשת, וזה יכול להתגלגל דרך מפתחות זרים. השתמשו בה רק כשאתם באמת מתכוונים ל"אם כבר יש שורה עם הערך הייחודי הזה, תזרוק אותה".
לרוב העבודה בסגנון upsert, התחביר הייעודי INSERT ... ON CONFLICT ברור יותר. יש על זה דף.
עטפו עדכונים מסוכנים בטרנזקציה
כשמשנים הרבה שורות או מריצים כמה פקודות UPDATE שצריכות להצליח יחד, עטפו אותן בטרנזקציה. אם משהו משתבש, אפשר לחזור למצב שלפני:
אם הפקודה השנייה נכשלת (נניח שאילוץ נכנס לפעולה), ROLLBACK מבטל את הראשונה. בלי טרנזקציה, הייתם נשארים עם העברה חצי גמורה: ל-Ada 25 פחות, ו-Boris ללא שינוי. לטרנזקציות יש פרק משלהן בהמשך. בינתיים פשוט דעו שהן קיימות, ושעדכונים גדולים כמעט תמיד שייכים לתוך אחת.
מלכודות נפוצות
רשימה קצרה של דברים שנושכים אנשים:
- שכחת
WHERE: מעדכנת כל שורה. קראו את הפקודה בקול לפני שאתם מריצים אותה. - אופרטור שגוי ב-
WHERE:WHERE status = NULLלא מתאים לשום דבר. השתמשו ב-IS NULL. נכסה את זה בדף על אופרטורים. - עדכון עם תת שאילתה שמחזירה יותר משורה אחת כשאתם מצפים לאחת. השתמשו ב-
LIMIT 1או בצבירה בתת השאילתה, אחרת תקבלו שגיאות או תוצאות מפתיעות. - בלבול בין UPDATE OR REPLACE ל-UPSERT.
OR REPLACEמוחק שורות מתנגשות.INSERT ... ON CONFLICT DO UPDATEמשנה אותן במקום. אלה פעולות שונות.
הבא בתור: DELETE
UPDATE משנה שורות. DELETE מסיר אותן. אותה משמעת של WHERE חלה, ואותו הרגל של "הריצו קודם SELECT" יציל אתכם מאותם סוגי אסונות. זה הדף הבא.
שאלות נפוצות
מה התחביר הבסיסי של UPDATE ב-SQLite?
UPDATE table_name SET column = value WHERE condition;. פסוקית SET מפרטת את העמודות שרוצים לשנות ואת הערכים החדשים שלהן. פסוקית WHERE בוחרת אילו שורות ישתנו: השמיטו אותה וכל שורה בטבלה תתעדכן.
איך מעדכנים כמה עמודות בפקודה אחת?
הפרידו את ההשמות בפסיקים בתוך פסוקית SET: UPDATE users SET name = 'Ada', email = 'ada@x.com' WHERE id = 1;. פקודה אחת, גישה אחת למסד הנתונים, שורה אחת מתעדכנת. אל תחזרו על SET לכל עמודה.
האם SQLite יכול לעדכן טבלה מתוך טבלה אחרת?
כן: UPDATE ... FROM (נוסף ב-SQLite 3.33) מאפשר לצרף טבלה אחרת או תת שאילתה לעדכון. כותבים UPDATE target SET col = source.col FROM source WHERE target.id = source.id;. זו הדרך הנקייה ביותר להעתיק ערכים בין טבלאות.