משיב מוביל
SQL Cascade Delete

שאלה
-
אהלן חברה , אני מתכנת בשפת C# יצרתי תוכנת ספר טלפונים אשר כל המידע המתקבל בתוכה נאגר במסדר נתונים sql server , במסד יש שלוש טבלאות persons groups phoneNumber עכשיו כמובן שלפי ההגיון הפשוט נרצה לעשות שכאשר אני אמחק קבוצה ימחקו כל אנשי הקשר שיש להם מפתח זר GROUPID שתואם לGROUPID שאני מוחק , או שכאשר אני אמחק איש קשר אז ימחקו כל מספרי הטלפון שיש להם מפתח זר PERSONID שתואם למפתח ראשי PERSONID בPERSONS לאיש קשר שאני מוחק.
כמובן שבכדי שעיקרון זה יצא לפועל הגדרי בקשרי גומלין את Delete כ-Cascade - כמו שאמרתי מוחק את כל השייכויות.
עכשיו כאשר ניסיתי למחוק קבוצה הכל עבד מצויין.
כשניסיתי למחוק קבוצה שיש פרסונים ששייכים לה זה זרק לי את השגיאה הבאה:
The DELETE statement conflicted with the REFERENCE constraint "FK_Persons_Groups". The conflict occurred in database "PhoneBook", table "dbo.Persons", column 'GroupID'.
לא הגדרתי שום אילוצים במסדר נתונים.
אני בטוח שיש איזה הגדרה שצריך להגדיר או להוריד ממנה את הוי כדי שזה יעבוד , אבל מכיוון שאני דיי חדש בSQL אז אני לא יודע אותה .תודה רבה לעוזרים
תשובות
-
איבן, דעה אישית אם מותר לי:
אנחנו לא צריכים להכין לאנשים את שיעורי הבית :-) מי שלא מספק DDL+DML אפשר לבקש ממנו וגם להסביר לו מה זה תוך כדי (רווח כפול... הוא ילמד משהו חדש). הגישה לדעתי צריכה להיות בפורום לעזור למי שנתקע בבעיה כדי שבפעם הבאה לא יתקע גם בבעיה אחרת דומה. בסגנון "תן לאדם דג והוא יהיה שבע היום אבל אם תלמד אותו לדוג הוא לא יהיה רעב יותר". ז"א גישה לימודית יותר מאשר לתת פתרון מוכן. מי שרוצה פתרון מוכן יכול להעסיק איש מקצוע בתשלום... לדעתי אנחנו כאן כדי לעזור לאנשי המקצוע ומי שלומד להיות בעתיד. בפורומים אחרים ברשת זו הגישה הרשמית דרך אגב. כאמור זה רק דעה וגישה אישית
היי רונן,
מסכים איתך לגמרי. פעם הבא אני אסביר איך עושים Script table as, למעשה, אני אעשה את זה תכף. :)
כנראה שלא מחקת את המפתח. בסקריפט שלי הוספתי בדיקה שמוחקת את ה-FK לפני יצירתו מחדש. עושים את זה עם לחיצת כפתור ימני על האובייקט ב-object explorer ואז script key as:
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Person_Group]') AND parent_object_id = OBJECT_ID(N'[dbo].[Person]')) ALTER TABLE [dbo].[Person] DROP CONSTRAINT [FK_Person_Group] GO ALTER TABLE [Person] WITH CHECK ADD CONSTRAINT [FK_Person_Group] FOREIGN KEY(GroupID) REFERENCES [dbo].[Group] (GroupID) ON DELETE CASCADE; GO
אתה רק צריך לתקן את השמות של טבלאות, עמודות ומפתח עצמו. כך תמחק אותו "על בטוח". :)
- סומן כתשובה על-ידי xbox2013 יום חמישי 11 אפריל 2013 16:36
כל התגובות
-
שלום גם לך.
קודם כל, פעם הבאה נא לספק לנו DDL (את המבנה של טבלאות שלך), על מנת שלא נצטרך לנחש ולבנות אותם לבד. בכל מקרה, אצלי זה עובד. אני יוצר את הטבלאות:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Person]') AND type in (N'U')) DROP TABLE [dbo].[Person] GO CREATE TABLE Person (PersonID int primary key, GroupID int not null, DetailID int not null) INSERT INTO Person VALUES (1,1,1) INSERT INTO Person VALUES (2,1,2) INSERT INTO Person VALUES (3,1,3) INSERT INTO Person VALUES (4,2,4) INSERT INTO Person VALUES (5,2,5) INSERT INTO Person VALUES (6,2,6) INSERT INTO Person VALUES (7,3,7) INSERT INTO Person VALUES (8,3,8) INSERT INTO Person VALUES (9,3,9) GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Group]') AND type in (N'U')) DROP TABLE [dbo].[Group] GO CREATE TABLE [Group] (GroupID int primary key) INSERT INTO [Group] VALUES (1) INSERT INTO [Group] VALUES (2) INSERT INTO [Group] VALUES (3) GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Detail]') AND type in (N'U')) DROP TABLE [dbo].[Detail] GO CREATE TABLE Detail (DetailID int primary key, PersonID int, Phone varchar (20)) INSERT INTO Detail VALUES (1,1,054) INSERT INTO Detail VALUES (2,2,054) INSERT INTO Detail VALUES (3,3,054) INSERT INTO Detail VALUES (4,4,054) INSERT INTO Detail VALUES (5,5,054) INSERT INTO Detail VALUES (6,6,054) INSERT INTO Detail VALUES (7,7,054) INSERT INTO Detail VALUES (8,8,054) INSERT INTO Detail VALUES (9,9,054) GO IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Person_Group]') AND parent_object_id = OBJECT_ID(N'[dbo].[Person]')) ALTER TABLE [dbo].[Person] DROP CONSTRAINT [FK_Person_Group] GO ALTER TABLE [Person] WITH CHECK ADD CONSTRAINT [FK_Person_Group] FOREIGN KEY(GroupID) REFERENCES [dbo].[Group] (GroupID) ON DELETE CASCADE; GO
אני מוחק את הקבוצה בעלת GroupID = 2:
DELETE FROM [Group] WHERE GroupID = 2
הקבוצה נמחקת יחד עם כל האנשים ששייכים עליה. תשווה את מה שעשיתי עם מה שעשית ותמצע את הבעיה.
לגבי השאלה שלך על אילוצים:
מפתח זר הוא האילוץ שהגדרת.
בהצלחה! :)
- הוצע כתשובה על-ידי pituachMVP, Moderator יום חמישי 11 אפריל 2013 11:14
-
תוספת: אני מניח שאתה בונה את הטבלאות לא כמו הדוגמה של איבן מעל ולא השתמשת למשל ב
ON DELETE CASCADE
תוספת זו קובעת בדיוק את מה שחסר כניראה וזה שמחיקה של הנתון בטבלה הראשית יגרור מחיקה של הנתונים המקושרים אליו. ברירת המחדל היא ללא תוספת זו ולכן כניראה הדברים לא עבדו אצלך.
אם אתה עובד עם EF CODE FIRST אז לא תהיה לך תוספת זו בברירת המחדל. אתה צריך להוסיף את זה ידנית אחרי יצירת המחלקות ואחרי שהטבלאות נוצרו או להוסיף הוראה במחלקה של צירת המודול למשל בשלב ה INIT או פשוט בבנאי שלה.
ALTER TABLE [Person] WITH CHECK -- CHECK constraint is used to limit the value range that can be placed in a column. ADD CONSTRAINT [FK_Person_Group] FOREIGN KEY(GroupID) REFERENCES [dbo].[Group] (GroupID) ON DELETE CASCADE -- Cascade will work when you delete something on Main Table [Group] GO
איבן, דעה אישית אם מותר לי:
אנחנו לא צריכים להכין לאנשים את שיעורי הבית :-) מי שלא מספק DDL+DML אפשר לבקש ממנו וגם להסביר לו מה זה תוך כדי (רווח כפול... הוא ילמד משהו חדש). הגישה לדעתי צריכה להיות בפורום לעזור למי שנתקע בבעיה כדי שבפעם הבאה לא יתקע גם בבעיה אחרת דומה. בסגנון "תן לאדם דג והוא יהיה שבע היום אבל אם תלמד אותו לדוג הוא לא יהיה רעב יותר". ז"א גישה לימודית יותר מאשר לתת פתרון מוכן. מי שרוצה פתרון מוכן יכול להעסיק איש מקצוע בתשלום... לדעתי אנחנו כאן כדי לעזור לאנשי המקצוע ומי שלומד להיות בעתיד. בפורומים אחרים ברשת זו הגישה הרשמית דרך אגב. כאמור זה רק דעה וגישה אישית
- נערך על-ידי pituachMVP, Moderator יום חמישי 11 אפריל 2013 11:24
-
קודם כל תודה על התגובות המהירות , אני אכן לא בונה טבלאות כמו בדוגמא של איבן.
הבנתי שאני צריך להוסיף את הקטע קוד שציינת (PITUACH) , מחקתי את הקשרי גומלין הקיימים (FK_PERSONS_GROUPS) פתחתי שאילתא חדשה ובה הכנסתי את הקוד שהבאת (כמובן עם שינויים מתאימים כגון איפה שרשמת PERSON כתבתי PERSONS וכ'ו) , ואז שעשיתי EXECUTE קיבלתי את השגיאה הבאה:Msg 2714, Level 16, State 4, Line 2
There is already an object named 'FK_Persons_Groups' in the database.
Msg 1750, Level 16, State 0, Line 2
Could not create constraint. See previous errors.הבנתי שהבעיה היא שכבר קיים הקשר הזה למרות שמחקתי אותו יש עוד איזשהי דרך למחוק אותו על בטוח?
או פשוט דרך אחרת של פשוט רק להוסיף את הפקודה שכנראה חסר לי שהיא :
ON DELETE CASCADE
תודה רבה , והמשך יום טוב.
-
תנסה לבדוק מה שכתב לך איבן
שים לב שבכל שאילתה של יצירת אלמנט חדש בעזרת CREATE הוא קודם בדק אם האלמנט קיים כבר בעזרת
IF EXISTS
אם הוא מצא שהאלמנט קיים אז הוא קודם מחק אותו לפני שבנה אותו מחדש. זה בדיוק הדרך בה אתה יכול לעבוד.
אני ממליץ שלא תעתיק קודים בלי להבין אבל אחרי שכבר יש לך את הקוד של איבן אתה יכול לעבור עליו שורה אחרי שורה ולוודא שאתה מבין בו כל מילה ומילה. אם יש משהו הכי קטן שאתה מבין אז תפנה מייד לגוגל הידיד הגדול של כל מפתח :-)
* אם גוגל לא מספיק אז אתה יכול להגיע לכאן עם השאלה אבל מפתח חייב לדעת ללמוד למצוא פתרונות לבד או לפחות לנסות.
אם הצלחת להבין את כל הקוד של איבן אז אתה יכול להישתמש בו או להתאים אותו לקוד שלך (למשל אם יש לך שדות בשם אחר)
** הערה: כשאתה מבקש עזרה כדאי מאוד לספק אינפורמציה כמו באיזה טכנולוגיה אתה עובד? כיצד אתה כי מייצר את הטבלאות וכו'
*** הערה: כדאי שתעבור על הקישור הבא כדי להבין על דיברנו כשהזכרנו את המילים DDL+DML. בכל שאלה במסדי נתונים כדאי לספק DDL+DML (זה מה שאיבן עשה בשבילך כרגע כדי שהוא יוכל לעזור).
במקרה שלך כניראה כל הבעיה קשורה רק ל DDL ולכן על אחת כמה וכמה חשוב לספק כיצד אתה ייצרת את האלמנטים אצלך. בכל מקרה נסה לעבור על הקוד של איבן ולהוציא משם את החלק של מחיקת האלמנטים ובכלל להבין את הקוד :-)
-
איבן, דעה אישית אם מותר לי:
אנחנו לא צריכים להכין לאנשים את שיעורי הבית :-) מי שלא מספק DDL+DML אפשר לבקש ממנו וגם להסביר לו מה זה תוך כדי (רווח כפול... הוא ילמד משהו חדש). הגישה לדעתי צריכה להיות בפורום לעזור למי שנתקע בבעיה כדי שבפעם הבאה לא יתקע גם בבעיה אחרת דומה. בסגנון "תן לאדם דג והוא יהיה שבע היום אבל אם תלמד אותו לדוג הוא לא יהיה רעב יותר". ז"א גישה לימודית יותר מאשר לתת פתרון מוכן. מי שרוצה פתרון מוכן יכול להעסיק איש מקצוע בתשלום... לדעתי אנחנו כאן כדי לעזור לאנשי המקצוע ומי שלומד להיות בעתיד. בפורומים אחרים ברשת זו הגישה הרשמית דרך אגב. כאמור זה רק דעה וגישה אישית
היי רונן,
מסכים איתך לגמרי. פעם הבא אני אסביר איך עושים Script table as, למעשה, אני אעשה את זה תכף. :)
כנראה שלא מחקת את המפתח. בסקריפט שלי הוספתי בדיקה שמוחקת את ה-FK לפני יצירתו מחדש. עושים את זה עם לחיצת כפתור ימני על האובייקט ב-object explorer ואז script key as:
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_Person_Group]') AND parent_object_id = OBJECT_ID(N'[dbo].[Person]')) ALTER TABLE [dbo].[Person] DROP CONSTRAINT [FK_Person_Group] GO ALTER TABLE [Person] WITH CHECK ADD CONSTRAINT [FK_Person_Group] FOREIGN KEY(GroupID) REFERENCES [dbo].[Group] (GroupID) ON DELETE CASCADE; GO
אתה רק צריך לתקן את השמות של טבלאות, עמודות ומפתח עצמו. כך תמחק אותו "על בטוח". :)
- סומן כתשובה על-ידי xbox2013 יום חמישי 11 אפריל 2013 16:36
-
-
-