בעיה בשאילתה רקורסיבית SQL
-
אני צריך לקבל באמצעות שאילתה רקורסיבית רשומה לכל שנה ושנה של עבודה עם החודשים שלה, תוכלו להעתיק את הקוד ולהדביק אותו ב SQL שלכם ולראות את התוצאה המשונה.
הקוד הזה לא מגיב בצורה הצפויה:--טבלה שאמורה להכיל את הנתונים ולעבד אותם לפני ההכנסה סופית למסד הנתונים declare @WorkingPlacesDetailed table (ID int IDentity(1,1) ,FromYear int, FromMonth int, ToYear int,ToMonth int, WorkingPlaceID int,WorkingPlaceName nvarchar(500),DeductionsNumber int,ParentID int); --ממלא את הטבלה בנתונים לדוגמא insert into @WorkingPlacesDetailed (FromYear , FromMonth , ToYear , ToMonth ,WorkingPlaceName) Values(2005,5,2010,9,'פורום חרדי לעניני תיכנות') ,(2010,11,2013,4,'ארגון דעאש'); --מוסיף רשומה לכל שנה בטבלה זו עצמה על סמך ההפרש בין השנים with cte as (select ID, FromYear y,FromMonth ,ToYear ,ToMonth , FromYear,WorkingPlaceName from @WorkingPlacesDetailed w where w.FromYear<w.ToYear union all select * from (select ID, y+1 y, (case when y = FromYear then FromMonth else 1 end) as FromMonth, ToYear, (case when y = ToYear then ToMonth else 12 end) as ToMonth, FromYear,WorkingPlaceName from cte ) as w where w.y <= w.ToYear) select y as Year,FromMonth , ToMonth , WorkingPlaceName ,ID as ParentID from cte Order by y ;
פורסם במקור בפורום CODE613 ב15/12/2014 15:56 (+02:00)
-
את התוצאה הסופית אפשר לקבל כך
insert into @WorkingPlacesDetailed (FromYear , FromMonth , ToYear , ToMonth ,WorkingPlaceName) Values(2005,5,2010,9,'פורום חרדי לעניני תיכנות') ,(2010,11,2013,4,'ארגון דעאש'); --מוסיף רשומה לכל שנה בטבלה זו עצמה על סמך ההפרש בין השנים with cte as (select ID, FromYear y,FromMonth ,ToYear ,ToMonth , FromYear,WorkingPlaceName from @WorkingPlacesDetailed w where w.FromYear<w.ToYear union all select * from (select ID, y+1 y, FromMonth, ToYear, ToMonth, FromYear,WorkingPlaceName from cte ) as w where w.y <= w.ToYear) select y as Year,(case when y = FromYear then FromMonth else 1 end) as FromMonth, (case when y = ToYear then ToMonth else 12 end) as ToMonth , WorkingPlaceName ,ID as ParentID , ToYear from cte Order by y ;
כך שהשאלה הפכה ממעשית לתיאורתית בינתיים, אם כי זה מאוד מוזר שהוא לא נותן תוצאה נורמלית ודרך הפעולה שלו לא מובנת.
פורסם במקור בפורום CODE613 ב15/12/2014 17:29 (+02:00)
-
ברגע שזה הפך לשאלה תיאורטית - זה התחום שלי . . .
בהחלט שישנו הגיון בכל זה - אבל הוא די מורכב - אנסה לעשות סדר
ישנן שתיים וחצי בעיות בדרך שבה ניסית לראשונה לפתור את הבעיה:
א. אתה מצפה לבצע מניפולציה על השורה הראשונה בכל מקום עבודה (להפוך את החודש ל 12) אבל את ה CASE שלך אתה שם רק בחלק השני של ה UNION והשורות האלו בכלל נבחרות בחלק הראשון שלו
ב. שכפלת את השדה FROMYEAR לשדה Y על מנת לבצע את המניפולציה על Y ולהשאיר את השדה המקורי לתצוגה ללא מניפולציה בכל השורות, מה שלא עשית בשדה TOMONTH ומכיוון שזו ריקורסיה זה גרם לכך שכשאתה מגיע לשורה האחרונה עבור מקום העבודה הערך בשדה TOMONTH נלקח מהשורה הקודמת שעשתה עליו מניפולציה ל 12 - ז"א התנאי ב CASE עובד אבל הערך שביקשת ממנו להביא הוא כבר לא הערך המקורי
ג. לא אהבתי את התת שאילתה אבל זה כבר עניין של טעם
הפתרון שלי הוא כזה
א. לשים באופן קשיח את החודש 12 ב TOMONTH בחלק הראשון של ה UNION ולשים 1 קשיח ב FROMMONTH בחלק השני של ה UNION
ב. להפריד את FROMMONTH לשדה נוסף שלא יבוצעו עליו מניפולציות לאורך הריקורסיה ואותו לשים בתנאי
ג. לשים Y+1 בכל השוואה ולחסוך את התת שאילתה
מה שאני חייב להודות שהפתרון של CASE בשאילתה הסופית הוא לא רע בכלל, לכן אני אוהב שהעניינים הופכים להיות עקרוניים ואפשר להתפלפל בלי לתת למציאות להפריע :lol:
הדוגמה שלי:
--טבלה שאמורה להכיל את הנתונים ולעבד אותם לפני ההכנסה סופית למסד הנתונים declare @WorkingPlacesDetailed table (ID int IDentity(1,1) ,FromYear int, FromMonth int, ToYear int,ToMonth int, WorkingPlaceID int,WorkingPlaceName nvarchar(500),DeductionsNumber int,ParentID int); --ממלא את הטבלה בנתונים לדוגמא insert into @WorkingPlacesDetailed (FromYear , FromMonth , ToYear , ToMonth ,WorkingPlaceName) Values(2005,5,2010,9,'פורום חרדי לעניני תיכנות') ,(2010,11,2013,4,'ארגון דעאש'); --מוסיף רשומה לכל שנה בטבלה זו עצמה על סמך ההפרש בין השנים with cte as (select ID, FromYear y,FromMonth ,ToYear, ToMonth m, 12 ToMonth, FromYear,WorkingPlaceName from @WorkingPlacesDetailed w where w.FromYear<w.ToYear union all select ID, y+1 y, 1 FromMonth, ToYear, m, (case when y+1 = ToYear then m else 12 end) as ToMonth, FromYear,WorkingPlaceName from cte w where w.y+1 <= w.ToYear) select y as Year,FromMonth , ToMonth , WorkingPlaceName ,ID as ParentID from cte Order by y
פורסם במקור בפורום CODE613 ב16/12/2014 02:00 (+02:00)