חישוב ימי עבודה בפועל

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

  • Post
    ofir
    משתתף
    שלום,

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

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

    לדוגמא : כניסה 01/01/17 יום א' יציאה 10/01/17 יום ג'
    סה"כ ימים מתאריך עד תאריך 10 ימים ,
    מתוכם שישי שבת – מופיע פעם אחת
    סה"כ ימי עבודה בפועל 8 ימים

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

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

    כיצד הייתם כותבים שאילתא שכזו?

מוצגות 15 תגובות – 1 עד 15 (מתוך 22 סה״כ)
  • Replies
    yitzchok
    משתתף
    IL
    לדעתי לא אמור להיות צורך לקרסור. (לעולם לנסות לא להשתמש בקרסור אם אפשר אחרת)

    הייתי הולך על משהו קרוב יותר לדבר השני שאתה מציע.

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

    חשוב לציין שאני לא יודע אם אתה צריך לבצע את החישוב רק עבור טווח תאריכים אחד או כמה – אבל בכל מצב לצערי לשפה של פריוריטי אין את האפשרויות שיש ב"טעמים" אחרים של SQL שנותנים לעשות כל מיני דברים "חכמים" תוך כדי אותה שאילתא.

    קודם כל אפשר לנהל טבלה של ימי חופש/חג. לא צריכים לשים שם שישי/שבת כי את אלה אפשר לחשב.

    הייתי עושה לולאה (לא קרסור) מהערך המספרי של התאריך הראשון (סוג DATE מחולק 24:00) עד האחרון. אם מדובר ב-א עד ה אז לספור. תקבל סה"כ ימי א-ה.

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

    וזהו… (?)

      [ בבקשה לא לשלוח הודעות פרטיות במערכת - אני לא קורא אותן ]
    yitzchok
    משתתף
    IL
    אם אתה רוצה להיות מאוד מקיף אפשר לעצב את טבלת ה"יוצאים מן הכלל" לאפשר רישום של ימי שישי ושבת כימי עבודה (אני מזכיר בגלל מוצ"ש…) ולעשות עוד חישוב שיוסיף ימים כאלה לספירה…
      [ בבקשה לא לשלוח הודעות פרטיות במערכת - אני לא קורא אותן ]
    אלמוני
    אורח
    לפני הרבה שנים כתבתי את הקוד למטה – הוא בודק את ההפרש בשבועות ואז מחסיר 2 לכל שבוע. היום אני די בטוח שניתן לכתוב את הפונקציה בצורה יותר קלה ויותר ברורה.


    :DAYS = 0;
    :DATE = 01/01/88;
    SELECT ((ORDSTATUSLOG.UDATE/24:00)*24:00),
    (((ORDSTATUSLOG.UDATE/24:00)*24:00) - ORDERS.CURDATE)/1440 -
    2 * (((WEEK (ORDSTATUSLOG.UDATE) / 100)*52 +
    WEEK (ORDSTATUSLOG.UDATE) MOD 100) -
    ((WEEK (ORDERS.CURDATE) / 100) * 52 +
    WEEK (ORDERS.CURDATE) MOD 100))
    INTO :DATE, :DAYS
    FROM ORDERS, ORDSTATUSLOG
    WHERE ORDERS.ORD = :ORD
    AND ORDERS.ORD = ORDSTATUSLOG.ORD
    AND ORDSTATUSLOG.ORDSTATUS = -2
    AND ORDSTATUSLOG.UDATE BETWEEN :$.FDT AND :$.TDT;

    ofir
    משתתף
    תודה על התשובות,

    במידה ואני צריך לחשב כ- 1000 רשומות שלכל רשומה יש טווח תאריכים שנע בין 5 ימים ל – 21 ימים ,

    האם לדעתכם תוכנית שכזו תהיה איטית בהכרח?

    yitzchok
    משתתף
    IL
    גם אם עושים את זה לא נורא יעיל זה לא יקח המון זמן.
    מי שיבין טוב יכול לבנות משהו שיקח מספר שניות גג.
      [ בבקשה לא לשלוח הודעות פרטיות במערכת - אני לא קורא אותן ]
    ofir
    משתתף
    כמה שניות? מעט מדי זמן לא??

    קו המחשב שלי הוא כך:
    מדובר על תעודות שהן קריאות שירות
    לכל תעודה יש START DATE ו- END DATE

    שלב 1- אוסף את כל ה- DOC ואת תאריך ההתחלה והסיום של כל תעודה לפי תנאים שהגדרתי מראש ואת אלו מכניס לתוך טבלה זמנית
    הטבלה מכילה : DOC , SDATE , EDATE , COUNT

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

    שלב 3- מוסר את הטבלה הזמנית לדוח שאותו אני מענויין להציג ושם מוסיף את העמודות הנוסופת הרצויות.

    מה דעתכם?

    yitzchok
    משתתף
    IL
    אפשר לחסוך הרבה.

    ושם מוסיף את העמודות הנוסופת הרצויות.

    איזה עמודות אתה צריך להוסיף?
    אם הכל בא מ-DOCUMENTS או לכל הפחות לא תטצרך לעשות עוד קיבוץ יכול להיות שתוכל לחסוך קצת הכנה מראש ולעשות את עיקר העבודה בשיטה שאני אתאר בתוך הדו"ח אבל אם תעשה את זה בשלב ההכנה אז יהיה לך יותר חופש באופן כללי.

    בינתיים נניח שתעשה את הכל בשלבי הכנה.

    הנחה נוספת: המקור שלך מסודר וכל תאריך סיום אחרי תאריך ההתחלה הקשור אליו.

    אני הייתי עושה כך:

    1. אוסף (MIN(SDATE ו- (MAX(EDATE על פני כל התעודות – נקרא לאלה MIN_SDATE ו-MAX_EDATE
    2. עושה לולאה פשוטה (לא קורסור). מתחיל מ-MIN_SDATE, בוחן אם מדובר בששי/שבת (או בתאריך של חופשים אחרים) ומדלג אם כן. (אם יש מצב של ששי/שבת שיכול להיות יום עבודה אז חזור למה שכתבתי קודם על נושא זה ושנה כאן בהתאם). את התאריך הזה מכניסים לטבלה (אם לא מדלגים) – טבלת STACK מצויינת לזה, רק לעשות 0+ כדי להפוך את התאריך למספר. וחוזר עד שמגיע ל-MAX_EDATE.
    3. עושה שאילתא על בסיס טבלת התעודות, וטבלת התאריכים מהשלב הקודם. עושים תנאי שהערך מטבלת התאריכים צריך להיות בין ה-SDATE וה-EDATE של התעודה (כולל, אם כך אתה רוצה) ואז קבץ לפי DOC ותוציא ספירה (COUNT) של מספר השורות שאתה מקבל לכל ערך של DOC. תוכל כאן לדעתי לדלג על שמירת SDATE ו-EDATE כי תוכל להביא אותם לדו"ח ביחד עם הערכים האחרים. כך שאתה צריך להכניס רק שני עמודות DOC ו-COUNT לאיזו טבלת לינק.
    4. כמו שלב 3 שלך

    מה דעתך?

      [ בבקשה לא לשלוח הודעות פרטיות במערכת - אני לא קורא אותן ]
    ofir
    משתתף
    שלום יצחק
    לא הבנתי כיצד אתה מדלג בכל פעם ביום מתאריך ההתחלה
    yitzchok
    משתתף
    IL
    אתה מתכוון לשלב 2 איך עוברים על כל התאריכים ללא קורסור?

    אם לא בבקשה לכתוב קצת על מה שכן הבנת ואיפה אתה נתקע.

      [ בבקשה לא לשלוח הודעות פרטיות במערכת - אני לא קורא אותן ]
    ofir
    משתתף
    כן. לשלב 2.
    yitzchok
    משתתף
    IL
    כתבתי

    2. עושה לולאה פשוטה (לא קורסור). מתחיל מ-MIN_SDATE, בוחן אם מדובר בששי/שבת (או בתאריך של חופשים אחרים) ומדלג אם כן. (אם יש מצב של ששי/שבת שיכול להיות יום עבודה אז חזור למה שכתבתי קודם על נושא זה ושנה כאן בהתאם). את התאריך הזה מכניסים לטבלה (אם לא מדלגים) – טבלת STACK מצויינת לזה, רק לעשות 0+ כדי להפוך את התאריך למספר. וחוזר עד שמגיע ל-MAX_EDATE.

    להלן דוגמה בסיסית של לולאה זו, ללא ההכנסה לטבלה. שמתי SELECT כדי להדגים.

    :MIN_SDATE = 01/01/17 ;
    :MAX_EDATE = 21/02/17 ;

    :LOOP_DATE = :MIN_SDATE ;
    LABEL 1 ;
    GOTO 2 WHERE DAY(:LOOP_DATE) IN (6,7) ; /* skip next section if Fri/Sat */

    SELECT :LOOP_DATE FROM DUMMY ASCII ;

    LABEL 2 ;
    :LOOP_DATE = :LOOP_DATE + 1440 ; /* add one day */
    LOOP 1 WHERE :LOOP_DATE <= :MAX_EDATE ; /* continue to next day unless last */

      [ בבקשה לא לשלוח הודעות פרטיות במערכת - אני לא קורא אותן ]
    אלמוני
    אורח
    הפתרון הזה דומה לספירת ימים באמצעות האצבעות, במקום להסיר תאריך אחד מהשני, תוך כדי התחשבות בסופי שבוע.
    yitzchok
    משתתף
    IL
    מסכים
    אבל אני נוקט בגישה שלי כי תומך בקלות בהורדת ימים נוספים שלא ימי עבודה אם רוצים.
    ועוד אני לא בדיוק הבנתי איך החישוב שלך עובד אז לא התייחסתי אליו.
      [ בבקשה לא לשלוח הודעות פרטיות במערכת - אני לא קורא אותן ]
    ofir
    משתתף
    נעם שלום
    הסבר בבקשה למה כוונתך
    להסיר תאריך אחד מהשני?
    ofir
    משתתף
    יצחק
    תודה על תשובתך
    בהנחה ויש לי מספר תעודות
    אני צריך לבצע את הללואה לכל תעודה?
מוצגות 15 תגובות – 1 עד 15 (מתוך 22 סה״כ)
  • יש להתחבר למערכת על מנת להגיב.