en-UShe-IL
You are here:   Blog > new Forums FAQ > Forums FAQ 347
Register   |  Login

כמה נקודות שיכולות לעזור

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

מה שמוצע כאן יהיה כבד מאוד למשל בהרצה בגרסת 2000 או אקסס ומסדים אחרים אם יהיה צורך לבצע את כל הפעולה עבור כל חודש בנפרד, ובסיום לחבר את כל התוצאות. על אחת כמה וכמה כשאר תרצה להשתמש בשיטה זו עבור מצבים יותר מורכבים כשלעיתים עלינו להחזיר הרבה יותר מ 12 נתונים של 12 חודשים בלבד, כמו במצב של פורום. נניח שרוצים להחזיר את כל הודעות התגובה הראשונות שיש בפורום (הודעות התגובה הראשונות הן כל ההודעות השניות ברמת ההירארכיה = מקביל לבעיה אצלך).

 

נתחיל מפתרון פשוט לגבי הבעיה שהציג גרי של חוסר בנתון:

הרעיון הראשון הוא פשוט מאוד להוסיף בשאילתה הראשונה בעזרת UNION שאילתה נוספת שתמיד תחזיר רשומה אחת. ז"א בתוצאה תמיד יהיה לנו עתה 1-3 רשמות שחוזרות במקום 0-2 רשומות שחזרו בלי הוספת הרשומה.

ברשומה הריקה שלנו אנחנו מכניסים אחד מ 2 ערכים שונים שיזהו עבורנו בהמשך האם היה חסר לנו נתון. למשל ניתן להכניס באחד השדות ערך כגון YES או NO במקרה של שדה טקסטואלי או ערך 0 ו 1 במקרה של שדה מספרי (סתם ננצל את אחד השדות הקיימים לצורך זה). כך למשל כאשר הערך יהיה YES אם יש 2 רשומות בסינון הקודם (בעזרת שאילתה פנימית) או ערך NO אחרת.

בשאילתה השנייה של ה TOP השני מסננים נתונים של רשומות עם ערך YES. לכן אם יש 2 נתונים מקוריים מקבלים את הנתון השני כמו שרצית, ואם אין נתון שני אז מקבלים למעשה את הרשומה הריקה שהוספנו.

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

 הרעיון השני הוא אפילו פשוט יותר. לבצע לפני השאילתה השניה על התוצאה סינון של הרשומות שאין להםנתון שני על ידי ביצוע בדיקה של count עם group by על השדה עליו מבצעים את החיבור נתונים

 

וכמה נקודות נוספות לגבי דרכים נוספות (ככל הנראה יותר יעילות) לפתרון הבעיה:

* הערה: ישנם מספר פתרונות שניתן לבחור וכל פתרון מתאים למסד נתונים שונה (אם בונים מנוע מיטוב אז אפשר לבחור את הפתרון המתאים כל פעם וליצור פונקציה או פרוצדורה שתבצע לנו את הפעולה)

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

** הערה: לכל שרתי הנתונים הגדולים קיים פתרון פשוט מובנה לייצר RANK או ROW_NUMBER אבל הלוגיקה שונה לחלוטין (למשל בחלק מהשרתים ניתן לבצע חישובים מתמטיים בין הרשומות בזמן ביצוע ה SELECT למשל מה שמאפשר לנו לבצע פעולה של עמודה שכל רשומה שווה לערך של העמודה הקודמת + 1)

*** ישנם גם שיטות ללא ניצול הייחודיות של השרתים השונים שיעבדו בכל מסד נתונים (באופן טבעי מעט יותר גוזלות משאבים)

 

לסיכום: אם אתה רוצה בנוסף לשיטות שהוצגו לך שיטות נוספות עלייך להגיע קודם כל להחלטה האם אתה רוצה שאילתה מכוונת מסד נתונים מסוים? או שאילתה כללית (על חשבון משאבים). כרגע ללא אפיון אנחנו זורקים פתרונות לבעיה לא ידועה.

 


 

רעיון כללי ליצירת RANK שיכול למטב את העבודה שלך בסדרי גודל תוכל למצוא בקישור הבא
https://ariely.info/dnn/Blog/tabid/83/EntryId/52/RANK-query-Without-using-RANK.aspx

רעיון כללי ליצירת Row_Number פשוט אפשר לבסס על שימוש ב RANK כאשר יש לך במערכת שדה ייחודי. למעשה אם תריץ את הרעיון הקודם על שדה ייחודי תקבל מיספור רשומות.

רעיון נוסף ליצירת Row_Number פשוט ובלי לכתוב הרבה קוד הוא פשוט להעביר את הנתונים לטבלה זמנית בה תוסיף שדה [MyRowNumber] [int] IDENTITY(1,1) NOT NULL. בטבלאות בהם אין לך אינדוס מתאים הרי שיש לך בכל מקרה לפחות סריקה אחת של הטבלה. העברת הנתונים לטבלה זמנית אותה תוכל גם לאנדקס ולמטב יכולה להיות לפעמים הדרך היעילה ביותר (גם מנוע המיטוב של השרת SQL לעיתים בוחר בצורה דומה של עבודה) . על ידי העברת הנתונים מסודרים כבר לפי הסדר המתאים לך והוספת שדה המספור האוטומטי קיבלת למעשה מספור של כל השורות כמו שרצית ואז נשאר רק לשלוף את הרשומות המתאימות

* ניתן לבנות פרוצדורה דינמית או פונקציה למשל בשם Row_Number2, אשר תמצא בצורה דינאמית את כל השדות שיש ותבנה טבלה בהתאם עם תוספת העמודה שלנו החדשה שלנו של המספור

select column_name from information_schema.columns

where table_name = 'ArielyTbl'

order by ordinal_position

וכך ל משל ניתן לראות כיצד מקבלים עמודת מספור

declare @Tbl as table ([MyRowNum] [int] IDENTITY(1,1) NOT NULL, [name] varchar(10))

insert @Tbl

select * from ArielyTbl order by ArielyRowNum.[name]

select * from @Tbl

 

 

לאחר שהגעת למצב שיש Row_number וכן של RANK כל הדלתות פתוחות עבורך :-)

אני חוזר שמדריך זה אינו מדבר על השיטות המיטביות כי אם על שיטות כלליות תוך עבודה בשאילתות פשוטות.

ניתן נחשב OVER של partition מסוים תוך שילוב של הנתונים הקיימים

row_number   RANK   name

1               1         a

2               1         a

3               3         d

4               3         d

5               3         d

 

חישוב פשוט של עמודה ראשונה פחות עמודה שנייה ועוד 1 נותן את התשובה

row_number   RANK   name   New

1            1      a      1-1+1 = 1

2            1      a      2-1+1 = 2

3            3      d      3-3+1 = 1

4            3      d      4-3+1 = 2

5            3      d      5-3+1 = 3