eehab_said بتاريخ: 11 أغسطس 2008 تقديم بلاغ مشاركة بتاريخ: 11 أغسطس 2008 لو سمحتم انا عايز فانكشن او بروسيدشر لحساب الفرق بين تاريخين بدون الجمعة او السبت لو وقع احدهما بين التاريخين اقتباس رابط هذا التعليق شارك المزيد من خيارات المشاركة
MMA بتاريخ: 11 أغسطس 2008 تقديم بلاغ مشاركة بتاريخ: 11 أغسطس 2008 الأخ الكريم ، قبل أي شيء يجب عليك معرفة محتويات التاريخين ... يعني بيتكون من أي شهور ( من البداية الي النهاية ) ... وتدرج كل هذه الشهور في جدول مستقل كما يلي : CREATE TABLE TMP_MONTHS ( DAT DATE; ) / DECLARE ID_START_DATE CONSTANT DATE := TO_DATE('24/9/1981','DD/MM/YYYY'); ID_END_DATE CONSTANT DATE := TO_DATE('24/9/2008','DD/MM/YYYY'); ID_DATE DATE; BEGIN ID_DATE := ID_START_DATE; WHILE ID_DATE <= ID_END_DATE LOOP ID_DATE := ID_DATE + 30.4375; INSERT INTO TMP_MONTHS VALUES(TO_DATE(TO_CHAR(ID_DATE,'YYYY/MM') || '1' ,'YYYY/MM/DD')); END LOOP; END; الآن أنت لديك جدول TEMP يحتوي علي كافة الشهور التي يحتوي عليها ما بين تاريخين ... يجب عليك الآن أن تمتلك جدول آخر أو عارض ليتضمن كافة أيام الشهر الممكنة كما يلي : CREATE TABLE DAYS ( D VARCHAR2(2); ) / DECLARE X NUMBER; BEGIN FOR X IN 1 .. 31 LOOP INSERT INTO DAYS VALUES(X); END LOOP; END; / السؤال ، لماذا لم يتم إدراج الأيام في جدول TMP_MONTHS علي الفور ... السبب لأن في هذه الحالة لو كان عدد السنوات 10 أو 20 أو 30 أو .... الي آخرة هيكون عملية الـ LOOP بطيئة بالزات أن كل سنة هتكون مكونة من 365 أو 366 يوم ... ولكن فكرة أنك تقم بإدراج جدول وسيط يدعي DAYS تدرج فية كل أيام الشهر دة في حد ذاتة هيخلي عملية الـ LOOP أقل وسرعة عالية نظراً لأن السنة في هذه الحالة ستحتوي علي 12 شهر يعني إجراء دوارة LOOP بمقدار 12 مرة وليس 365 أو 366 لكل سنة.المهمطريقة الدمج بين الشهر واليوم :1- إنشاء FUNCTION يدعي IS_DATE لهدف أنه ليس من الشرط أن يكون كل شهر يحتوي علي 31 يوم : CREATE OR REPLACE FUNCTION IS_DATE(IN_TEXT VARCHAR2) RETURN NUMBER AS ID_DATE DATE; BEGIN ID_DATE := TO_DATE(IN_TEXT,'YYYY/MM/DD'); RETURN 1; EXCEPTION WHEN OTHERS THEN RETURN 0; END; / بعد ذلك تنشأ VIEW لجلب كل أيام الشهور بل السنوات كما يلي : CREATE OR REPLACE LIST_ALL_DAYS AS ( SELECT TO_DATE(TO_CHAR(TMP_MONTHS.DAT,'YYYY/MM/DD') || DAYS.D,'YYYY/MM/DD') AS DAY FROM TMP_MONTHS, DAYS WHERE IS_DATE(TO_DATE(TO_CHAR(TMP_MONTHS.DAT,'YYYY/MM/DD') || DAYS.D,'YYYY/MM/DD')) = 1 ) / بكدة هيكون لديك جدول كامل يحتوي علي كل الأيام المطلوبة للسنوات ... ولكن أنتبه يجب عليك إجراء تحديث دوري علي جدول TMP_MONTHS نظراً لتغير القيمة المدخلة كل مرة .الآن إليك إجابة سؤالك الخاص ، كيف يمكننا إيجاد عدد أيام بين تاريخين دون إحتساب يومي الجمعة أو السبت ... أنظر الكود : CREATE OR REPLACE FUNCTION GET_COUNT_DAYS(IN_START DATE, IN_END DATE,) RETURN NUMBER AS ID_DATE DATE; ID_RETURN NUMBER; BEGIN --1: تحديث جدول الشهور أولاً. ID_DATE := ID_START_DATE; WHILE ID_DATE <= ID_END_DATE LOOP ID_DATE := ID_DATE + 30.4375; INSERT INTO TMP_MONTHS VALUES(TO_DATE(TO_CHAR(ID_DATE,'YYYY/MM') || '1' ,'YYYY/MM/DD')); END LOOP; --2: إيجاد عدد الأيام المناسبة دون يومي السبت والجمعة. SELECT COUNT(*) INTO ID_RETURN FROM LIST_ALL_DAYS WHERE LIST_ALL_DAYS.DAY BETWEEN IN_START AND IN_END AND TO_CHAR (LIST_ALL_DAYS.DAY,'D') IN NOT (1,7) REUTN ID_RETURN; END; / بالتوفيق اقتباس رابط هذا التعليق شارك المزيد من خيارات المشاركة
weloooo بتاريخ: 14 أغسطس 2008 تقديم بلاغ مشاركة بتاريخ: 14 أغسطس 2008 ودي طريقه تانيه لعمل ما تريدمن هنا اقتباس رابط هذا التعليق شارك المزيد من خيارات المشاركة
MMA بتاريخ: 15 أغسطس 2008 تقديم بلاغ مشاركة بتاريخ: 15 أغسطس 2008 الأخ الكريم ( أحمد يحيي ) أشكرك كل الشكر علي هذا الـ Function الأكثر من روعة ... بس أسمح لي بأن أوضح بعض الأمورقاعدة البيانات عاملة زي معالج الحاسب Processor ... وكما تعلم أن المعالج لا يفهم سوي الإشارات الرقمية الثنائية ( لغة آلة ) ... فكلما أقتربت من لغة الآلة كلما كانت العملية أسرع بكثير ... بس هيبقي فية صعوبة التصميم والبرمجة ... لكن لو أبتعدت عن لغة الآلة يعني مثلاً أستخدمت لغة برمجة مثل الفيجوال 6.0 أو الدوت نيت فهتكون العملية سهلة جداً بس هيكون أبطأ نسبياً .تخيل حضرتك أنك ستصنع Function يعمل Loop علي أساس 25 سنة حضور وإنصارف لموظف محدد ... وكل سنة 365.25 يوم يعني ( 365.25 × 12 = 4383 ) ... في كل مرة سيقوم بإجراء الـ Loop ويؤدي الي توقف مؤقت فترة ( وذلك يرجع الي عدد العمليات المدرجة داخل جملة الـ Loop ) ... أنظر الي العملية البسيطة التالية : Set ServerOutput On Declare X Number; Y Number; Begin DBMS_Output.Put_Line(To_Char(SysDate,'HH24:MI:SS')); For X In 1 .. 4383 Loop Select Count(*) Into Y From Tab; End Loop; DBMS_Output.Put_Line(To_Char(SysDate,'HH24:MI:SS')); End; / رغم أنها عملية بسيطة ولكنها أخذت مني علي سرعة معالج 256 ورامات 512 بمقدار 12 ثواني ... ولكن ماذا لو كان العميل لدية حاسب أضعف ... عموماً الثانية لو كانت أقل من الملي ثانية بالطبع هيكون أفضل بكثير .لكن لو صنعنا Loop بسيط وبعد ذلك إستخدمنا جمل الـ SQL هيكون أسرعلذلك أقول أن كلما أقتربنا من الـ SQL هيكون العملية أسرع بكثير من الـ PL خصوصاً لو كانت العملية تتطلب الي عرض أكثر من سجل ... وكل سجل يحتوي علي 3 أو 4 أو 5 أو -------------- ؟ حقول ... وكل حقل يتضمن Function يأخز وقت ثقيل بسبب جملة Loop .أنا لا أقول أن الـ PL/SQL ضعيف ... ولا أقل أن الـ Loop غير مطلوب ... ولكنني أقول بأن كل صح له الأصح منهعلي فكرة أخي أنا والله جربت هذه الفكرة من قبل ... بس عجبتني الفكرة التي أدرجتها لأنها فعلاً بسيطة وواضحة وفي نفس الوقت أسرع بكثير ... مجرد تنفذ مرة واحدة وبعد كدة تجلب الي أنت عايزة .شكراً ، وبالتوفيق للجميع ، اقتباس رابط هذا التعليق شارك المزيد من خيارات المشاركة
weloooo بتاريخ: 17 أغسطس 2008 تقديم بلاغ مشاركة بتاريخ: 17 أغسطس 2008 كلامك صحيح يا أخ مصطفى وأنا معاك. عشان كده إحنا ممكن نعمل حاجه ظريفه زياده على الفانكشن دي:نستخدم تقنية ال forall ونعمل temp table ثم نقوم بعملية إدخال للأيام غير الجمعه والسبت وبعد كده نعمل count للسجلات وتقريباًَ ده هايكون كويس جداً لعملية ال performance .طبعاً لابد وأن نضع في الحسبان الآداء . اقتباس رابط هذا التعليق شارك المزيد من خيارات المشاركة
Recommended Posts
انضم إلى المناقشة
يمكنك المشاركة الآن والتسجيل لاحقاً. إذا كان لديك حساب, سجل دخولك الآن لتقوم بالمشاركة من خلال حسابك.