PL/SQL أساسيات PDF
Document Details
![InstrumentalLemur](https://quizgecko.com/images/avatars/avatar-14.webp)
Uploaded by InstrumentalLemur
aBOULFATEH
Tags
Summary
هذا المستند هو دليل PL/SQL، وهو يشرح اللغة بلغة العربية. يتضمن الموضوعات الأساسية مثل الكتل والإجراءات وأمثلة. يمكن استخدامه من قبل المبرمجين لتعلم PL/SQL.
Full Transcript
**PL/SQL** **ما هي لغة PL/SQL؟** **PL/SQL** هي لغة برمجة متقدمة اختصاراً Procedural Language/Structured Query Language\ و امتداد للغة SQL (Structured Query Language). طورتها شركة Oracle لتوفير قدرات برمجة إجرائية أقوى داخل بيئة قواعد البيانات العلائقية. بمعنى آخر، فهي تسمح لك بإنشاء برامج أكثر تعق...
**PL/SQL** **ما هي لغة PL/SQL؟** **PL/SQL** هي لغة برمجة متقدمة اختصاراً Procedural Language/Structured Query Language\ و امتداد للغة SQL (Structured Query Language). طورتها شركة Oracle لتوفير قدرات برمجة إجرائية أقوى داخل بيئة قواعد البيانات العلائقية. بمعنى آخر، فهي تسمح لك بإنشاء برامج أكثر تعقيدًا من مجرد كتابة استعلامات SQL البسيطة. **لماذا نستخدم PL/SQL؟** - **التحكم في المعاملات:** تسمح لك PL/SQL بتجميع عدة عمليات SQL داخل كتلة واحدة (بلوك)، وبالتالي التحكم في المعاملات بشكل أفضل. يمكنك إجراء عدة تغييرات على قاعدة البيانات ضمن معاملة واحدة، وإما تأكيد جميع التغييرات أو إلغائها جميعًا في حالة حدوث خطأ. - **إجراء عمليات حسابية معقدة:** يمكنك تنفيذ عمليات حسابية معقدة، واتخاذ قرارات بناءً على نتائج هذه الحسابات، وتكرار عمليات معينة باستخدام حلقات. - **تخصيص قاعدة البيانات:** يمكنك إنشاء إجراءات مخزنة (stored procedures) ودوال (functions) لتأدية مهام محددة، مما يزيد من كفاءة قاعدة البيانات ويقلل من تكرار الكود. - **التفاعل مع المستخدم:** يمكنك إنشاء واجهات مستخدم بسيطة للتفاعل مع المستخدم، مثل عرض رسائل أو طلب إدخال بيانات. - **البرمجة الشيئية:** تدعم PL/SQL بعض مفاهيم البرمجة الشيئية، مثل الكائنات والوراثة، مما يجعلها لغة أكثر مرونة وقوة. **ميزات PL/SQL:** - **لغة إجرائية:** توفر PL/SQL بنية تحكم إجرائية مثل الحلقات والشروط والدوال، مما يتيح كتابة برامج معقدة ومنظمة. - **تكامل : SQL** يمكن تضمين أوامر SQL مباشرة داخل برامج PL/SQL، مما يسهل استرجاع وتحديث البيانات. - **أمان البيانات** : توفر PL/SQL آليات أمان مدمجة تساعد في حماية البيانات وضمان سلامتها. - **أدوات تطوير متكاملة: Oracle** توفر أدوات تطوير متقدمة لكتابة واختبار وتصحيح برامج PL/SQL. - **أداء محسّن :** يمكن تحسين أداء الاستعلامات والبرامج باستخدام PL/SQL من خلال تنفيذها داخل قاعدة البيانات. **مكونات أساسية في PL/SQL:** - **الكتلة (Block):** هي الوحدة الأساسية للبرنامج في PL/SQL. تتكون من قسم الإعلان (declaration section)، وقسم التنفيذ (execution section)، وقسم الاستثناءات (exception section). - **المتغيرات والثوابت:** تستخدم لتخزين القيم بشكل مؤقت خلال تنفيذ البرنامج. - **أنواع البيانات:** تدعم PL/SQL مجموعة متنوعة من أنواع البيانات، مثل الأعداد، النصوص، والتاريخ. - **العمليات الحسابية:** يمكنك إجراء عمليات حسابية أساسية مثل الجمع والطرح والضرب والقسمة. - **الجمل الشرطية:** تستخدم لاتخاذ قرارات بناءً على شروط معينة (مثل IF-THEN-ELSE). - **الحلقات:** تستخدم لتكرار مجموعة من الأوامر عدة مرات (مثل FOR loop، WHILE loop). - **الإجراءات والمهام:** هي برامج مخزنة يمكن استدعاؤها من أي مكان في قاعدة البيانات. - **الدوال:** هي برامج مخزنة تعيد قيمة واحدة. **أمثلة على استخدام PL/SQL:** - **تحقق من صحة البيانات المدخلة:** قبل حفظ البيانات في قاعدة البيانات، يمكنك التحقق من صحتها للتأكد من أنها تتوافق مع القواعد المحددة. - **إنشاء تقارير معقدة:** يمكنك إنشاء تقارير مخصصة تجمع البيانات من مصادر مختلفة وعرضها في شكل جذاب. - **أتمتة المهام:** يمكنك أتمتة مهام متكررة، مثل إرسال رسائل بريد إلكتروني أو تحديث البيانات بشكل دوري. - **تحسين أداء قاعدة البيانات:** يمكنك استخدام PL/SQL لكتابة كود أكثر كفاءة، مما يؤدي إلى تحسين أداء قاعدة البيانات. **لماذا تتعلم PL/SQL ؟** إذا كنت تعمل مع قواعد بيانات Oracle، فإن تعلم PL/SQL يعتبر ضروريًا لكي تتمكن من: - **الاستفادة الكاملة من قدرات قاعدة البيانات:** يمكنك إنشاء تطبيقات أكثر تعقيدًا ومرونة. - **تحسين أداء التطبيقات:** يمكنك كتابة كود أكثر كفاءة. - **تخصيص قاعدة البيانات:** يمكنك تكييف قاعدة البيانات لتلبية الاحتياجات الخاصة لتطبيقك. **أمثلة على استخدام PL/SQL:** - كتابة إجراءات مخزنة لتنفيذ مهام محددة داخل قاعدة البيانات. - إنشاء وتنفيذ استعلامات معقدة تتضمن التحكم في التدفق والشروط. - تطوير تطبيقات ويب متكاملة تعتمد على قواعد البيانات. ### أساسيات PL/SQL: 1. **الكتل**: الكتلة هي الوحدة الأساسية في PL/SQL وتتكون من: - جمل تهيئة (declarations) - جمل التنفيذ (execution) - جمل المعالجة الاستثنائية (exception handling) PL/SQL Block ------------------------ -------------------------------- قسم الإعلان (اختياري) Declaration Section (Optional) إعلانات المتغيرات Variable Declarations قسم التنفيذ Execution Section استعلامات/عبارات SQL SQL Queries/Statements المنطق الإجرائي Procedural Logic قسم معالجة الاستثناءات Exception Handling Section منطق معالجة الأخطاء Error Handling Logic مثال:- DECLARE v\_message VARCHAR2(50) := \'Hello, PL/SQL!\'; BEGIN DBMS\_OUTPUT.PUT\_LINE(v\_message); EXCEPTION WHEN OTHERS THEN DBMS\_OUTPUT.PUT\_LINE(\'An error occurred.\'); END; / طريقة مختصرة BEGIN جمل التنفيذ -- DBMS\_OUTPUT.PUT\_LINE (\'Hello, World!\'); END; / 2. **الإجراءات والوظائف**: يتم إنشاء الإجراءات والوظائف لإعادة استخدام الأكواد وتنفيذ العمليات المعقدة. مثال على إجراء بسيط: CREATE OR REPLACE PROCEDURE greet (name IN VARCHAR2) IS BEGIN DBMS\_OUTPUT.PUT\_LINE(\'Hello, \' \|\| name); END; / 3. **الحزم**: الحزم تجمع بين الإجراءات والوظائف المتشابهة في وحدة واحدة، مما يسهل إدارة الأكواد الكبيرة والمعقدة. CREATE OR REPLACE PACKAGE my\_package IS PROCEDURE greet(name IN VARCHAR2); END my\_package; / في PL/SQL، هناك شروط يجب أن تلتزم بها عند تسمية المتغيرات. إليك بعض الشروط الأساسية لتسمية المتغيرات في PL/SQL: **شروط تسمية المتغيرات في: PL/SQL** 1. يجب أن تبدأ أسماء المتغيرات بحرف. 2. يمكن أن تتكون أسماء المتغيرات من حروف (كبيرة وصغيرة) وأرقام وشرطة سفلية (\_) فقط. 3. يجب أن لا تحتوي أسماء المتغيرات على أي رموز خاصة مثل @ وغيرها. 4. يجب أن تكون أسماء المتغيرات فريدة داخل نطاق البرنامج. **أنواع البيانات في PL/SQL** تقدم PL/SQL مجموعة واسعة من أنواع البيانات لتخزين قيم مختلفة. إليك شرح مختصر لأهم هذه الأنواع: - **رقمي (Numeric):** - **: NUMBER** يستخدم لتخزين الأعداد الصحيحة والعشرية. يمكن تحديد الدقة والتسوية. - **INTEGER** : يستخدم لتخزين الأعداد الصحيحة فقط. - **: BINARY\_INTEGER** يستخدم لتخزين الأعداد الصحيحة الثنائية. - **نصي (Character):** - **VARCHAR2** : يستخدم لتخزين سلسلة أحرف ذات طول محدد. - **: CHAR** يستخدم لتخزين سلسلة أحرف ذات طول ثابت. - **: CLOB** يستخدم لتخزين نصوص كبيرة الحجم. - **تاريخ ووقت (Date and Time):** - **DATE** : يستخدم لتخزين التاريخ والوقت. - **منطقي : Boolean** - **: BOOLEAN** يستخدم لتخزين قيم منطقية (صحيح أو خطأ). - **كائنات كبيرة : LARGE OBJECT (LOB)** - **: BLOB** يستخدم لتخزين بيانات ثنائية كبيرة الحجم (مثل الصور والصوت). - **: BFILE** هذا النوع يستخدم لتخزين مسار ملف موجود خارج قاعدة البيانات. لا يخزن الملف نفسه داخل قاعدة البيانات، بل يشير إلى مكانه على نظام الملفات. - **أخرى : others** Data Type Maximum Size in PL/SQL Maximum Size in SQL ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ CHAR 32,767 bytes 2,000 bytes NCHAR [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#fnsrc_d28297e529) 32,767 bytes 2,000 bytes RAW [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#fnsrc_d28297e542) 32,767 bytes 2,000 bytes [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#GUID-C3B938C9-7B0B-4AAC-8323-FEB2ED0225D0__CJAGGFGH) VARCHAR2 [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#fnsrc_d28297e563) 32,767 bytes 4,000 bytes [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#fnsrc_d28297e571) NVARCHAR2 [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#fnsrc_d28297e578) 32,767 bytes 4,000 bytes [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#fnsrc_d28297e586) LONG [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#GUID-C3B938C9-7B0B-4AAC-8323-FEB2ED0225D0__CJAFECGG) 32,760 bytes 2 gigabytes (GB) - 1 LONG RAW [[ ]](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-data-types.html#fnsrc_d28297e610) 32,760 bytes 2 GB BLOB 128 terabytes (TB) (4 GB - 1) \* *database\_block\_size* CLOB 128 TB (4 GB - 1) \* *database\_block\_size* NCLOB 128 TB (4 GB - 1) \* *database\_block\_size* : Data Types with Different Maximum Sizes in PL/SQL and SQL **مثال** DECLARE v\_short\_text VARCHAR2(50) ; \-- متغير نصي بطول 50 حرفًا v\_long\_text VARCHAR2(32767) ; \-- متغير نصي بطول 32767 حرفًا v\_fixed\_text CHAR(10) ; \-- متغير نصي ثابت الطول بطول 10 أحرف v\_large\_text CLOB; متغير نصي كبير\-- BEGIN استخدام المتغيرات في الكود \-- v\_short\_text := \'Hello, World\'; v\_fixed\_text := \'FixedLen\' ; v\_large\_text := \'This is a large text stored in CLOB type\' ; DBMS\_OUTPUT.PUT\_LINE(v\_short\_text); DBMS\_OUTPUT.PUT\_LINE(v\_fixed\_text); DBMS\_OUTPUT.PUT\_LINE(SUBSTR(v\_large\_text, 1, 20)) ; \-- عرض أول 20 حرفًا فقط END; / مالمقصود ب **ROWID** ؟ **ROWID** هو معرف فريد يعطى لكل صف داخل جداول قاعدة البيانات في أوراكل. يمثل ROWID العنوان الفعلي للصف في قاعدة البيانات، مما يجعله أسرع وسيلة للوصول إلى الصفوف. يحتوي ROWID على معلومات حول الموقع الفعلي للصف على القرص. ### مميزات ROWID: - **أداء عالي**: استخدام ROWID في الاستعلامات يمكن أن يحسن من الأداء بشكل كبير، لأنه يعرض الصف مباشرة دون الحاجة إلى فحص الفهارس. - **معرف فريد**: كل صف له ROWID خاص به، مما يعني أنه يمكنك دائمًا تحديد الصف بشكل فريد باستخدام ROWID. ### صيغة ROWID: ROWID يتكون من أربعة مكونات: 1. **الكتالوج**: معرف الفتحة التي تحتوي على الصف. 2. **الملف**: معرف الملف. 3. **الكتلة**: معرف الكتلة التي تحتوي على الصف. 4. **الصف**: موقع الصف داخل الكتلة. مثال على كيفية استخدام ROWID في PL/SQL استعراض \`ROWID\` للصفوف في جدول معين \-- SELECT ROWID, employee\_name FROM employees; استخدام \`ROWID\` لتحديد صف معين \-- DECLARE v\_rowid ROWID; BEGIN SELECT ROWID INTO v\_rowid FROM emp WHERE ename = \'ABOULFATEH\'; \-- استخدام \`ROWID\` لتحديث الصف المحدد UPDATE emp SET sal = sal \* 1.1 WHERE ROWID = v\_rowid; END; / في هذا المثال، يتم أولاً استرجاع ROWID للصفوف في جدول emp ثم يتم استخدام ROWID لتحديد صف معين وتحديث راتب الموظف المسمى \'ABOULFATEH\'. استخدام ROWID يمكن أن يكون مفيدًا في العمليات التي تتطلب أداء عالي وتحديد الصفوف بدقة. ما هو ROWNUM في Oracle ؟ ------------------------ **ROWNUM** هو رقم تسلسلي يعين بشكل مؤقت للصفوف عند استرجاعها من قاعدة بيانات Oracle نتيجة لاستعلام ما. بعبارة أبسط، هو رقم يبدأ من 1 ويزداد بـ 1 لكل صف يتم استرجاعه. **لماذا نستخدم ROWNUM ؟** - **تحديد عدد الصفوف المسترجعة :** يمكن استخدام ROWNUM لتحديد عدد معين من الصفوف التي تريد استرجاعها. على سبيل المثال، لاسترجاع أول 10 صفوف من جدول، يمكنك استخدام: - **ترقيم الصفوف** : يمكن استخدام ROWNUM لترقيم الصفوف في نتيجة الاستعلام. - الاستخدام في عبارات شرطية: يمكن استخدام ROWNUM في عبارات شرطية معقدة. **ملاحظات هامة حول ROWNUM:** - **غير ثابت:** قيمة ROWNUM تتغير مع كل تنفيذ للاستعلام. - **يعتمد على ترتيب الصفوف:** رقم الصف الذي يحصل عليه كل صف يعتمد على ترتيب الصفوف في نتيجة الاستعلام. إذا لم تحدد ترتيبًا محددًا للصفوف باستخدام عبارة ORDER BY، فإن الترتيب قد يختلف من مرة إلى أخرى. - **لا يمكن استخدامه في عبارة WHERE قبل عبارة ORDER BY:** إذا كنت تريد استخدام ROWNUM في عبارة WHERE، يجب أن تكون عبارة ORDER BY موجودة قبلها. **مثال آخر:** SELECT \* FROM emp WHERE deptno = 20 ORDER BY sal DESC WHERE ROWNUM \، \= 18 THEN\ DBMS\_OUTPUT.PUT\_LINE(\'أنت بالغ\'); END IF;\ END;\ / ### 2. الجملة الشرطية IF\...ELSE تستخدم هذه الجملة لتنفيذ مجموعة من الأوامر إذا كان الشرط صحيحًا ومجموعة أخرى إذا كان الشرط خاطئًا. IF الشرط THEN\ الأوامر التي يتم تنفيذها إذا كان الشرط صحيحًا\--\ ELSE\ الأوامر التي يتم تنفيذها إذا كان الشرط خاطئًا\--\ END IF; **مثال:** ### 3. الجملة الشرطية IF\...ELSIF تستخدم هذه الجملة عندما يكون هناك أكثر من شرط يجب فحصه. IF الشرط1 THEN\ الأوامر التي يتم تنفيذها إذا كان\-- الشرط1 صحيحًا\ ELSIF الشرط2 THEN ![](media/image4.png)\ الأوامر التي يتم تنفيذها إذا كان الشرط2 - صحيحًا\ ELSE\ الأوامر التي يتم تنفيذها إذا كانت جميع \-- الشروط خاطئة\ END IF; **مثال:** DECLARE\ v\_grade NUMBER :=85;\ BEGIN\ IF v\_grade \>= 90 THEN\ DBMS\_OUTPUT.PUT\_LINE(\'امتياز\'); ELSIF v\_grade \>= 80 THEN\ DBMS\_OUTPUT.PUT\_LINE(\'جيد جدًا\'); ELSE\ DBMS\_OUTPUT.PUT\_LINE(\'مقبول\');\ END IF;\ END;\ / ### 4. الجملة الشرطية CASE تستخدم هذه الجملة للتحقق من قيمة تعبير واحد مقابل قيم متعددة. CASE التعبير\ WHEN القيمة1 THEN\ \-- الأوامر التي يتم تنفيذها إذا كانت القيمة تساوي القيمة1\ WHEN القيمة2 THEN\ \-- الأوامر التي يتم تنفيذها إذا كانت القيمة تساوي القيمة2\ ELSE\ \-- الأوامر التي يتم تنفيذها إذا لم تتطابق القيمة مع أي من القيم السابقة\ END CASE; **مثال:** DECLARE\ v\_day NUMBER := 3;\ BEGIN\ CASE v\_day\ WHEN 1 THEN\ DBMS\_OUTPUT.PUT\_LINE(\'الأحد\');\ WHEN 2 THEN\ DBMS\_OUTPUT.PUT\_LINE(\'الاثنين\');\ \-- \...\ ELSE DBMS\_OUTPUT.PUT\_LINE(\'يوم غير صالح\');\ END CASE;\ END;\ / **ملحوظات:** - يمكن استخدام مشغلي المقارنة مثل =, !=, \>, \=, \ - **مثال:** - **الشكل العام:** ### 2. حلقة WHILE - **الاستخدام:** تستخدم عندما نريد تكرار مجموعة من الأوامر طالما أن شرطًا معينًا صحيحًا. - **الشكل العام:** - **المخطط:** - **مثال:** ### 3. حلقة LOOP - **الاستخدام:** حلقة عامة يمكن استخدامها لإنشاء أي نوع من التكرار. تتطلب استخدام عبارة EXIT أو EXIT WHEN لإنهاء الحلقة. - **الشكل العام:** - **المخطط:** - **مثال:** عبارة FOR LOOP REVERSE هي طريقة بسيطة وفعالة لتنفيذ حلقة FOR بحيث تبدأ من القيمة النهائية وتنتهي بالقيمة الأولية، أي بعكس الترتيب الطبيعي للحلقة. هذا مفيد عندما نريد معالجة مجموعة من القيم بترتيب تنازلي بدلاً من تصاعدي. **تركيب الحلقة:** FOR loop\_counter IN REVERSE lower\_bound.. upper\_bound\ LOOP\ \-- مجموعة الأوامر التي سيتم تنفيذها في كل تكرار للحلقة\ END LOOP; - **loop\_counter:** متغير عداد يحمل قيمة التكرار الحالي. - **lower\_bound:** القيمة الصغرى (أو النهائية) التي يبدأ منها العد. - **upper\_bound:** القيمة العظمى (أو الأولية) التي ينتهي عندها العد. **مثال:** لنفترض أننا نريد طباعة الأعداد من 10 إلى 1 بترتيب تنازلي: DECLARE\ i NUMBER;\ BEGIN\ FOR i IN REVERSE 10..1\ LOOP\ DBMS\_OUTPUT.PUT\_LINE(i);\ END LOOP;\ END;\ / **الشرح:** 1. **الإعلان عن المتغير:** يتم إعلان المتغير i من نوع NUMBER ليكون عداد الحلقة. 2. **بدء الحلقة:** تبدأ الحلقة من القيمة 10 (النهائية) وتنتهي بالقيمة 1 (الأولية)، بحيث يتناقص قيمة i في كل تكرار. 3. **جسم الحلقة:** داخل الحلقة، يتم طباعة قيمة i الحالية باستخدام DBMS\_OUTPUT.PUT\_LINE. 4. **نهاية الحلقة:** عند الوصول إلى نهاية الحلقة، يتم تكرار الخطوات من 2 إلى 3 حتى تصبح قيمة i أقل من 1. **مخرجات هذا المثال:** 10\ 9\ 8\ 7\ 6\ 5\ 4\ 3\ 2\ 1 **استخدامات أخرى:** - **معالجة مصفوفات أو سجلات بترتيب عكسي:** يمكن استخدام FOR LOOP REVERSE لمعالجة عناصر مصفوفة أو سجلات جدول بترتيب عكسي. - **تنفيذ عمليات حسابية بترتيب معين:** يمكن استخدامها لتنفيذ عمليات حسابية تبدأ من قيمة نهائية وتنتهي بقيمة أولية. - **إنشاء تقارير بترتيب تنازلي:** يمكن استخدامها لإنشاء تقارير تعرض البيانات بترتيب تنازلي حسب حقل معين. **الوحدات البرمجية في أوراكل** **الوحدات البرمجية في PL/SQL: المسماة وغير المسماة** **مقدمة** في لغة PL/SQL، الوحدات البرمجية هي اللبنات الأساسية لبناء التطبيقات. هذه الوحدات تُستخدم لتنظيم الكود وتقسيمه إلى أجزاء أصغر قابلة لإعادة الاستخدام. يمكن تصنيف هذه الوحدات إلى نوعين رئيسيين: 1. **الوحدات البرمجية غير المسماة (Anonymous Blocks):** - **تعريف:** هي كتل من الكود لا تحمل اسمًا محددًا وتُنفذ بشكل مباشر عند كتابتها. - **البنية:** SQL\ DECLARE\ \-- إعلانات المتغيرات والثوابت\ BEGIN\ \-- التعليمات البرمجية التي يتم تنفيذها\ END;\ / - **الاستخدامات:** - **اختبارات سريعة:** لاختبار قطع صغيرة من الكود بسرعة. - **مهام بسيطة:** لتنفيذ مهام بسيطة لا تتطلب إنشاء إجراءات أو دوال معقدة. - **تنفيذ واحد:** يتم تنفيذ الكود مرة واحدة فقط عند تشغيل الوحدة. - **مثال:** DECLARE\ v\_employee\_name VARCHAR2(30) := \'علي\';\ BEGIN\ DBMS\_OUTPUT.PUT\_LINE(\'اسم الموظف هو: \' \|\| v\_employee\_name);\ END;\ / 2. **الوحدات البرمجية المسماة:** - **تعريف:** هي كتل من الكود تحمل اسمًا محددًا ويمكن استدعاؤها من أي مكان في البرنامج. - **أنواعها:** - **الإجراءات (Procedures):** لا ترجع قيمة. - **الدوال (Functions):** ترجع قيمة واحدة. - **الحزم (Packages):** مجموعة من الإجراءات والدوال والأنواع والمتغيرات ذات الصلة. - **البنية:** CREATE OR REPLACE PROCEDURE procedure\_name\ IS\ \-- إعلانات المتغيرات المحلية\ BEGIN\ \-- التعليمات البرمجية\ END;\ / - **الاستخدامات:** - **إعادة الاستخدام:** يمكن استدعاء الوحدة المسماة من أي مكان في البرنامج. - **التنظيم:** تساعد في تنظيم الكود وتقسيمه إلى وحدات وظيفية. - **المعايير:** يمكن تمرير معلمات إلى الوحدة المسماة. - **الاستثناءات:** يمكن التعامل مع الأخطاء والاستثناءات داخل الوحدة. - **مثال:** CREATE OR REPLACE PROCEDURE get\_employee\_name\ (p\_employee\_id IN NUMBER,\ p\_employee\_name OUT VARCHAR2)\ IS\ BEGIN\ SELECT first\_name INTO p\_employee\_name\ FROM employees\ WHERE employee\_id = p\_employee\_id;\ END;\ / **متى تستخدم كل نوع؟** - **الوحدات غير المسماة:** - لاختبارات سريعة وبسيطة. - لمهام لا تتكرر. - عندما لا تحتاج إلى إعادة استخدام الكود. - **الوحدات المسماة:** - لإعادة استخدام الكود. - لتنظيم الكود الكبير. - لإنشاء واجهات برمجية (APIs). - للتعامل مع الأخطاء والاستثناءات. **الاختلافات الرئيسية** الميزة الوحدات غير المسماة الوحدات المسماة ----------------- ------------------------------------- --------------------------------- الاسم لا يوجد اسم محدد يحمل اسمًا محددًا إعادة الاستخدام لا يمكن إعادة استخدامها مباشرة يمكن إعادة استخدامها من أي مكان المعلمات لا تدعم المعلمات تدعم المعلمات الاستثناءات يمكن التعامل معها لكن ليس بشكل منظم يمكن التعامل معها بشكل منظم التنظيم أقل تنظيمًا أكثر تنظيمًا **الخلاصة** كل من الوحدات البرمجية المسماة وغير المسماة لها دورها في تطوير تطبيقات PL/SQL. اختيار النوع المناسب يعتمد على متطلبات التطبيق وحجم الكود. بشكل عام، يجب استخدام الوحدات المسماة لتنظيم الكود وإعادة استخدامه، بينما يمكن استخدام الوحدات غير المسماة لاختبارات سريعة ومهام بسيطة. **ملاحظات:** - يمكن دمج الوحدات غير المسماة داخل الوحدات المسماة. - الحزم هي طريقة قوية لتنظيم الوحدات البرمجية وتوفير مستوى أعلى من التجريد. **الوحدات البرمجية المسماه** ### 1. الحزم (Packages): - **تعريف:** هي مجموعة من الإجراءات، الدوال، المتغيرات، الأنواع، والاستثناءات التي يتم تجميعها في وحدة واحدة. - **الغرض:** توفر إعادة الاستخدام، التنظيم، و التغليف (Encapsulation). - **مثال:** حزمة لحساب العمليات الحسابية الأساسية ### 2. الإجراءات (Procedures): - **تعريف:** مجموعة من الأوامر التي تقوم بتنفيذ مهمة معينة. - **الغرض:** لا تقوم بإرجاع قيمة، ولكنها تستخدم لتنفيذ مجموعة من العمليات. - **مثال:** إجراء لإدراج صف جديد في جدول. ### 3. الدوال (Functions): - **تعريف:** تشبه الإجراءات ولكنها تقوم بإرجاع قيمة من نوع معين. - **الغرض:** تستخدم في الحسابات والتعبير عن قيم. - **مثال:** دالة لحساب الجذر التربيعي لعدد. ### 4. الأنواع (Types): - **تعريف:** تسمح بإنشاء أنواع بيانات مخصصة. - **الغرض:** تستخدم لتمثيل هياكل بيانات معقدة. - **مثال:** نوع لتمثيل موظف يحتوي على اسم، رقم، وراتب. ### 5. المؤشرات (Cursors): - **تعريف:** تسمح بالوصول إلى البيانات في جدول بشكل صف بصف. - **الغرض:** تستخدم للتحكم في تنفيذ الأوامر SQL. - **مثال:** مؤشر لعرض جميع الموظفين في قسم معين. ### 6. الاستثناءات (Exceptions): - **تعريف:** تستخدم للتعامل مع الأخطاء غير المتوقعة التي قد تحدث أثناء تنفيذ الكود. - **الغرض:** تضمن استمرارية عمل التطبيق عند حدوث أخطاء. - **مثال:** استثناء لمعالجة حالة عدم وجود صف. ### 7. القادحات (Triggers): - **تعريف:** هي إجراءات أو دوال يتم تنفيذها تلقائيًا استجابة لحدث معين في قاعدة البيانات. - **الغرض:** تستخدم لتنفيذ عمليات تلقائية عند حدوث تغييرات في البيانات. - **مثال:** زاجر لزيادة الرصيد في جدول حساب بنكي عند إجراء إيداع. **لماذا تستخدم الوحدات البرمجية في أوراكل؟** - **إعادة الاستخدام:** يمكن استخدام الوحدات البرمجية في أماكن متعددة في قاعدة البيانات. - **التنظيم:** تساعد في تنظيم الكود وجعله أكثر قابلية للقراءة والصيانة. - **الأمان:** يمكن التحكم في الوصول إلى الوحدات البرمجية. - **الكفاءة:** يمكن تحسين أداء التطبيقات باستخدام الوحدات البرمجية. **الدوال (Functions)** ---------------------- الدوال (Functions) في لغة PL/SQL هي عبارة عن وحدات برمجية مصممة لأداء مهمة محددة وإرجاع قيمة واحدة من نوع بيانات معين. تُستخدم الدوال لتنفيذ عمليات حسابية، منطقية، أو استرجاع قيم من قاعدة البيانات، مما يساهم في تحسين قابلية قراءة الكود وإعادة استخدامه. ### بنية الدالة الأساسية تتكون الدالة بشكل عام من الأجزاء التالية: 1. **كلمة المفتاح FUNCTION:** تحدد بداية تعريف الدالة. 2. **اسم الدالة:** هو الاسم الذي يتم استخدامه لاستدعاء الدالة. 3. **قائمة المعلمات:** تحدد القيم التي يتم تمريرها إلى الدالة عند استدعائها. 4. **نوع البيانات المرجعة:** يحدد نوع البيانات التي ستقوم الدالة بإرجاعها. 5. **الجزء التنفيدي:** يحتوي على الأوامر التي تقوم بتنفيذ منطق الدالة. 6. **عبارة RETURN:** تستخدم لإرجاع القيمة النهائية للدالة. **الصيغة العامة:** CREATE OR REPLACE FUNCTION function\_name (parameter1 IN data\_type, parameter2 IN data\_type, \...) RETURN return\_data\_type IS \-- إعلانات المتغيرات المحلية BEGIN \-- التعليمات البرمجية RETURN result; END; / **مثال:** CREATE OR REPLACE FUNCTION get\_employee\_age ) p\_birth\_date IN employees.birth\_date%TYPE)\ RETURN NUMBER IS\ v\_age NUMBER;\ BEGIN\ \-- حساب العمر باستخدام وظائف تاريخ\ v\_age := \...;\ RETURN v\_age;\ END;\ / ### مزايا استخدام الدوال - **إعادة الاستخدام:** يمكن استدعاء الدالة من أي مكان في الكود، مما يقلل من تكرار الكود. - **قابلية القراءة:** تجعل الكود أكثر وضوحًا وسهولة في الصيانة. - **التنظيم:** تساعد في تنظيم الكود وتقسيمه إلى وحدات وظيفية أصغر. - **الكفاءة:** يمكن تحسين أداء التطبيقات عن طريق استخدام الدوال. ### أنواع الدوال - **الدوال البسيطة:** تقوم بتنفيذ عمليات حسابية بسيطة وإرجاع قيمة واحدة. - **الدوال المعقدة:** يمكن أن تحتوي على منطق تحكم، استدعاءات لدوال أخرى، ومعالجة استثناءات. - **الدوال المحددة مسبقًا:** هي دوال يتم توفيرها بواسطة أوراكل، ويمكن تصنيف الدوال المحددة مسبقًا في أوراكل إلى عدة فئات: - **دوال التحويل:** تستخدم لتحويل البيانات من نوع إلى آخر. - **مثال:** TO\_CHAR, TO\_DATE, TO\_NUMBER - **الدوال الحسابية:** تستخدم لإجراء عمليات حسابية. - **مثال:** SQRT, ROUND, TRUNC - **الدوال النصية:** تستخدم لمعالجة النصوص. - **مثال:** UPPER, LOWER, SUBSTR - **الدوال التاريخية:** تستخدم للعمل مع التواريخ والأزمنة. - **مثال:** ADD\_MONTHS, LAST\_DAY - **دوال مجموعة:** تستخدم لإجراء عمليات على مجموعات من البيانات. - **مثال:** COUNT, SUM, AVG - **دوال أخرى:** تغطي مجالات متنوعة مثل التحقق من وجود القيم، المقارنات، وغيرها. - **مثال:** NVL, DECODE, CASE - **الدوال المخصصة:** هي دوال يتم تعريفها من قبل المستخدم. ### استخدامات الدوال - **الحسابات:** إجراء عمليات حسابية مثل الجمع، الطرح، الضرب، القسمة، الجذور، وغيرها. - **التحويل:** تحويل البيانات من نوع إلى آخر، مثل تحويل التاريخ إلى نص أو العكس. - **الاستعلام عن البيانات:** استرجاع قيم من قاعدة البيانات بناءً على شروط معينة. - **التحقق من صحة البيانات:** التأكد من صحة البيانات المدخلة. - **العمليات المنطقية:** اتخاذ قرارات بناءً على شروط معينة. ### ### ### ### أمثلة على الدوال - **دالة لحساب مساحة المستطيل:** - **دالة للتحقق من رقم هاتف:** ### الختام الدوال هي أداة قوية في PL/SQL تساعد في بناء تطبيقات قواعد البيانات بشكل أكثر كفاءة ومرونة. من خلال فهم مفهوم الدوال واستخدامها بشكل صحيح، يمكنك كتابة كود أكثر قابلية للقراءة والصيانة وإعادة الاستخدام. **ملاحظات هامة:** - يمكن للدالة أن تستدعي دوال أخرى. - يمكن تعريف الدوال داخل الحزم (Packages) لتنظيم الكود بشكل أفضل. - يمكن استخدام الدوال في عبارات SQL، مثل عبارات WHERE و HAVING. **ملاحظات إضافية:** - **المعلمات:** يمكن أن تكون المعلمات إدخال (IN) أو إخراج (OUT) أو إدخال وإخراج (IN OUT). - **الاستثناءات:** يمكن التعامل مع الاستثناءات داخل الدوال باستخدام الكلمات المفتاحية EXCEPTION و WHEN. - **الدوال المتداخلة:** يمكن تعريف دوال داخل دوال أخرى. - **الدوال الزائدة التحميل:** يمكن تعريف أكثر من دالة بنفس الاسم ولكن بمعلمات مختلفة. **مثال : أنشىء دالة بلغة PL/SQL للتحقق من وجود موظف في جدول معين بناءً على رقم الموظف:** CREATE OR REPLACE FUNCTION is\_employee\_exists\ (p\_employee\_id IN employees.employee\_id%TYPE(\ RETURN BOOLEAN IS\ v\_count NUMBER;\ BEGIN\ SELECT COUNT(\*) INTO v\_count\ FROM employees\ WHERE employee\_id = p\_employee\_id;\ \ IF v\_count \ 0 THEN\ RETURN TRUE;\ ELSE\ RETURN FALSE;\ END IF;\ END;\ / **كيفية استدعاء الدالة:** DECLARE\ v\_employee\_exists BOOLEAN;\ BEGIN \-- \-- افترض أن 7788 هو رقم موظف v\_employee\_exists := is\_employee\_exists (7788) ;\ IF v\_employee\_exists THEN\ DBMS\_OUTPUT.PUT\_LINE(\'الموظف موجود\') ;\ ELSE\ DBMS\_OUTPUT.PUT\_LINE(\'الموظف غير موجود\') ;\ END IF;\ END;\ / **1. دالة لحساب مجموع رقمين** CREATE OR REPLACE FUNCTION add\_numbers (num1 IN NUMBER, num2 IN NUMBER)\ RETURN NUMBER\ IS\ result NUMBER;\ BEGIN\ result := num1 + num2;\ RETURN result;\ END;\ /\ \ \-- استدعاء الدالة\ DECLARE\ sum\_result NUMBER;\ BEGIN\ sum\_result := add\_numbers(10, 20);\ DBMS\_OUTPUT.PUT\_LINE(\'مجموع الرقمين هو: \' \|\| sum\_result);\ END;\ / **2. دالة للتحقق من عدد زوجي أو فردي** CREATE OR REPLACE FUNCTION is\_even (num IN NUMBER)\ RETURN VARCHAR2\ IS\ BEGIN\ IF MOD(num, 2) = 0 THEN\ RETURN \'زوجي\';\ ELSE\ RETURN \'فردي\';\ END IF;\ END;\ /\ \ \-- استدعاء الدالة\ DECLARE\ number\_type VARCHAR2(10);\ BEGIN\ number\_type := is\_even(5);\ DBMS\_OUTPUT.PUT\_LINE(\'العدد 5 هو: \' \|\| number\_type);\ END;\ / **3. دالة لإيجاد أكبر عدد من ثلاثة أعداد** CREATE OR REPLACE FUNCTION find\_max (num1 IN NUMBER, num2 IN NUMBER, num3 IN NUMBER)\ RETURN NUMBER\ IS\ BEGIN\ IF num1 \>= num2 AND num1 \>= num3 THEN\ RETURN num1;\ ELSIF num2 \>= num1 AND num2 \>= num3 THEN\ RETURN num2;\ ELSE\ RETURN num3;\ END IF;\ END;\ /\ \ \-- استدعاء الدالة\ DECLARE\ max\_number NUMBER;\ BEGIN\ max\_number := find\_max(15, 25, 10);\ DBMS\_OUTPUT.PUT\_LINE(\'أكبر عدد هو: \' \|\| max\_number);\ END;\ / **4. دالة لتحويل الحروف إلى أحرف كبيرة** CREATE OR REPLACE FUNCTION upper\_case (str IN VARCHAR2)\ RETURN VARCHAR2\ IS\ BEGIN\ RETURN UPPER(str);\ END;\ /\ \ \-- استدعاء الدالة\ DECLARE\ upper\_string VARCHAR2(30);\ BEGIN\ upper\_string := upper\_case(\'ahmed\');\ DBMS\_OUTPUT.PUT\_LINE(\'الحروف الكبيرة: \' \|\| upper\_string);\ END;\ / **5. دالة لحساب طول سلسلة نصية** CREATE OR REPLACE FUNCTION string\_length (str IN VARCHAR2)\ RETURN NUMBER\ IS\ BEGIN\ RETURN LENGTH(str);\ END;\ /\ \ \-- استدعاء الدالة\ DECLARE\ str\_length NUMBER;\ BEGIN\ str\_length := string\_length(\'hello world\');\ DBMS\_OUTPUT.PUT\_LINE(\'طول السلسلة: \' \|\| str\_length);\ END;\ / **6. دالة لإرجاع اسم الموظف بناءً على رقم الموظف** CREATE OR REPLACE FUNCTION get\_employee\_name (p\_empno IN employees.empno%TYPE)\ RETURN employees.ename%TYPE\ IS\ v\_ename employees.ename%TYPE;\ BEGIN\ SELECT ename INTO v\_ename\ FROM employees\ WHERE empno = p\_empno;\ RETURN v\_ename;\ EXCEPTION\ WHEN NO\_DATA\_FOUND THEN\ DBMS\_OUTPUT.PUT\_LINE(\'لا يوجد موظف بهذا الرقم\');\ RETURN NULL;\ END;\ /\ \-- استدعاء الدالة\ DECLARE\ v\_name VARCHAR2(20);\ BEGIN\ v\_name := get\_employee\_name(7369);\ DBMS\_OUTPUT.PUT\_LINE(\'اسم الموظف هو: \' \|\| v\_name);\ END;\ / **7. دالة لحساب متوسط رواتب الموظفين في قسم معين** CREATE OR REPLACE FUNCTION get\_avg\_salary (p\_deptno IN employees.deptno%TYPE)\ RETURN NUMBER\ IS\ v\_avg\_sal NUMBER;\ BEGIN\ SELECT AVG(sal) INTO v\_avg\_sal\ FROM employees\ WHERE deptno = p\_deptno;\ RETURN v\_avg\_sal;\ EXCEPTION\ WHEN NO\_DATA\_FOUND THEN\ DBMS\_OUTPUT.PUT\_LINE(\'لا يوجد موظفين في هذا القسم\');\ RETURN NULL;\ END;\ /\ \ \-- استدعاء الدالة\ DECLARE\ v\_avg\_sal NUMBER;\ BEGIN\ v\_avg\_sal := get\_avg\_salary(20);\ DBMS\_OUTPUT.PUT\_LINE(\'متوسط الراتب في القسم 20 هو: \' \|\| v\_avg\_sal);\ END;\ / **8. دالة لزيادة رواتب جميع الموظفين بنسبة مئوية معينة** CREATE OR REPLACE PROCEDURE increase\_salaries (p\_percent IN NUMBER)\ IS\ BEGIN\ UPDATE employees\ SET sal = sal \* (1 + p\_percent/100);\ END;\ /\ \ \-- استدعاء الإجراء (ملاحظة: هذه دالة إجرائية لا ترجع قيمة)\ BEGIN\ increase\_salaries(10); \-- زيادة الرواتب بنسبة 10%\ END;\ / **9. دالة لإيجاد عدد الموظفين في كل قسم** CREATE OR REPLACE FUNCTION get\_dept\_count (p\_deptno IN employees.deptno%TYPE)\ RETURN NUMBER\ IS\ v\_count NUMBER;\ BEGIN\ SELECT COUNT(\*) INTO v\_count\ FROM employees\ WHERE deptno = p\_deptno;\ RETURN v\_count;\ END;\ /\ \ \-- استدعاء الدالة\ DECLARE\ v\_count NUMBER;\ BEGIN\ v\_count := get\_dept\_count(30);\ DBMS\_OUTPUT.PUT\_LINE(\'عدد الموظفين في القسم 30 هو: \' \|\| v\_count);\ END;\ / **10. دالة لإرجاع اسم الوظيفة بناءً على رقم الوظيفة** CREATE OR REPLACE FUNCTION get\_job\_title (p\_job\_id IN employees.job\_id%TYPE)\ RETURN jobs.job\_title%TYPE\ IS\ v\_job\_title jobs.job\_title%TYPE;\ BEGIN\ SELECT job\_title INTO v\_job\_title\ FROM jobs\ WHERE job\_id = p\_job\_id;\ RETURN v\_job\_title;\ EXCEPTION\ WHEN NO\_DATA\_FOUND THEN\ DBMS\_OUTPUT.PUT\_LINE(\'لا يوجد وظيفة بهذا الرقم\');\ RETURN NULL;\ END;\ /\ \ \-- استدعاء الدالة\ DECLARE\ v\_job\_title VARCHAR2(30);\ BEGIN\ v\_job\_title := get\_job\_title(\'SA\_REP\');\ DBMS\_OUTPUT.PUT\_LINE(\'اسم الوظيفة هو: \' \|\| v\_job\_title);\ END;\ / **الإجراءات البرمجية (Procedures)** **ما هي الإجراءات البرمجية في PL/SQL؟** الإجراء (Procedure) في PL/SQL هو عبارة عن كتلة من التعليمات البرمجية التي يتم تنفيذها عند استدعائها. تستخدم الإجراءات لأتمتة المهام المتكررة، وتنفيذ عمليات معقدة على البيانات، وتقسيم منطق التطبيق إلى وحدات أصغر. **متى نستخدم الإجراءات؟** - **أتمتة المهام:** يمكن استخدام الإجراءات لأتمتة المهام الروتينية مثل تحديث البيانات، وإرسال رسائل البريد الإلكتروني، وإنشاء تقارير. - **تنفيذ عمليات معقدة:** يمكن استخدام الإجراءات لتنفيذ عمليات معقدة تتطلب عدة خطوات. - **إعادة الاستخدام:** يمكن استدعاء الإجراء مرة واحدة وتنفيذها من أماكن متعددة في الكود. - **تحسين القابلية للقراءة والصيانة:** يمكن تقسيم الكود إلى إجراءات أصغر لتسهيل فهمه وصيانته. **هيكل الإجراء** يتكون الإجراء بشكل عام من: - **الرأس (Header):** يحدد اسم الإجراء والمعلمات التي يأخذها. - **البدن (Body):** يحتوي على التعليمات البرمجية التي يتم تنفيذها عند استدعاء الإجراء. CREATE OR REPLACE PROCEDURE my\_procedure(\ p\_parameter1 IN NUMBER,\ p\_parameter2 OUT VARCHAR2\ ) IS\ \-- تعليمات الإجراء هنا\ BEGIN\ \-- \...\ END my\_procedure; **معلمات الاجراء** - **IN:** معلمة إدخال يتم تمرير قيمتها إلى الإجراء. - **OUT:** معلمة مخرج يتم إرجاع قيمة منها إلى المُستدعي. - **IN OUT:** معلمة يمكن قراءتها وكتابتها داخل الإجراء. **مثال على إجراء بسيط** CREATE OR REPLACE PROCEDURE increase\_salary(\ p\_employee\_id IN employees.employee\_id%TYPE,\ p\_increase\_amount IN NUMBER\ ( IS\ BEGIN\ UPDATE employees\ SET salary = salary + p\_increase\_amount\ WHERE employee\_id = p\_employee\_id;\ END increase\_salary; **استدعاء الإجراء** BEGIN\ \-- زيادة راتب الموظف رقم 7900 بـ 500\--\ increase\_salary(7900, 500); END;\ / **ميزات الإجراءات** - **مرونة:** يمكن تمرير مختلف أنواع البيانات كمعلمات للإجراءات. - **إعادة الاستخدام:** يمكن استدعاء الإجراء من أي مكان في قاعدة البيانات. - **التنظيم:** تساعد الإجراءات على تنظيم الكود وتحسين قابلية الصيانة. - **الاستثناءات:** يمكن التعامل مع الأخطاء باستخدام كتلة EXCEPTION. **أمثلة أخرى لأستخدامات الإجراءات** - **إجراء عمليات حسابية معقدة:** يمكن كتابة إجراءات لحساب القيم الإحصائية أو المالية. - **إرسال رسائل البريد الإلكتروني:** يمكن استخدام الإجراءات لإرسال رسائل إلكترونية تلقائية بناءً على أحداث معينة. - **إنشاء تقارير:** يمكن إنشاء إجراءات لتوليد تقارير مخصصة. - **تحقق من صحة البيانات:** يمكن استخدام الإجراءات للتحقق من صحة البيانات المدخلة قبل تخزينها في قاعدة البيانات. **ملاحظات هامة** - **لا ترجع قيمة:** على عكس الدوال، لا ترجع الإجراءات قيمة بشكل مباشر. يتم استخدام المعلمات النمط OUT لإرجاع القيم. - **يمكنها تنفيذ أي عدد من العمليات:** يمكن للإجراء تنفيذ أي عدد من العمليات، بما في ذلك تحديث الجداول، وإدراج سجلات جديدة، وحذف سجلات، واستدعاء إجراءات أخرى. - **يمكنها استدعاء دوال أخرى:** يمكن للإجراء استدعاء دوال أخرى لتنفيذ مهام محددة. **1. إجراء لحساب مجموع رواتب الموظفين** CREATE OR REPLACE PROCEDURE calc\_total\_salary\ IS\ v\_total\_salary NUMBER:=0;\ BEGIN\ SELECT SUM(salary) INTO v\_total\_salary\ FROM employees;\ \ DBMS\_OUTPUT.PUT\_LINE(\'مجموع الرواتب =\'\|\| v\_total\_salary);\ END;\ / \--استدعاء الدالة BEGIN calc\_total\_salary; END; / **2. إجراء لزيادة راتب موظف بقيمة معينة بناءا على رقمة** CREATE OR REPLACE PROCEDURE update\_emp\_sal (\ p\_emp\_id IN emp.empno%TYPE,\ p\_sal IN emp.sal%TYPE)\ IS\ BEGIN\ UPDATE emp\ SET sal = sal+ p\_sal\ WHERE empno = p\_emp\_id;\ END;\ / \--استدعاء الدالة BEGIN update\_emp\_sal(7369, 100); \-- يزيد راتب الموظف رقم 7369 بمقدار 100 END; / **3. إجراء لإدراج موظف جديد** CREATE OR REPLACE PROCEDURE insert\_employee\ ) p\_empno IN emp.empno%TYPE,\ p\_ename IN emp.ename%TYPE,\ p\_job IN emp.job%TYPE,\ p\_sal IN emp.sal%TYPE, p\_mgr IN emp.mgr%TYPE, p\_hiredate IN emp.hiredate%TYPE, p\_deptno IN emp. deptno %TYPE)\ \ AS\ BEGIN\ INSERT INTO emp (empno,ename,job,sal,mgr,hiredate,deptno) VALUES (p\_empno, p\_ename, p\_job, p\_sal,p\_mgr, p\_hiredate, p\_deptno); COMMIT;\ EXCEPTION\ WHEN DUP\_VAL\_ON\_INDEX THEN استثناء في حال ادخال رقم موظف موجود \--\ DBMS\_OUTPUT.PUT\_LINE(\'Employee number already exists\' ( ; END;\ / \--استدعاء الدالة\ BEGIN insert\_employee( p\_empno =\> 8000, p\_ename =\>\'ABOULFATEH\', p\_job =\> \'ANALYST\', p\_sal =\> 1500, p\_mgr =\> 7902, p\_hiredate =\> TO\_DATE(\'2024-12-25\', \'YYYY-MM-DD\'), p\_deptno =\> 20 , ); END; / **4. إجراء لحذف موظف** CREATE OR REPLACE PROCEDURE delete\_employee\ (p\_emp\_id IN emp.empno%TYPE(\ IS\ BEGIN\ DELETE FROM emp\ WHERE empno = p\_emp\_id;\ END;\ / \--استدعاء الدالة BEGIN delete\_employee (7900); \-- حذف بيانات الموظف رقم 7900 END; **5. إجراء للتحقق من وجود موظف** CREATE OR REPLACE PROCEDURE check\_employee\_exists\ (p\_empno IN emp.empno%TYPE,\ p\_exists OUT number(\ IS\ BEGIN\ SELECT COUNT (\*) INTO p\_exists\ FROM employees\ WHERE empno = p\_empno;\ END;\ / \--استدعاء الدالة DECLARE v\_exists NUMBER; BEGIN check\_employee\_exists(7369, v\_exists); \-- استدعاء الإجراء IF v\_exists \> 0 THEN DBMS\_OUTPUT.PUT\_LINE(\'الموظف موجود\'); ELSE DBMS\_OUTPUT.PUT\_LINE(\'الموظف غير موجود\'); END IF; END; / **6. إجراء لزيادة رواتب جميع الموظفين بنسبة مئوية معينة** CREATE OR REPLACE PROCEDURE increase\_salaries\ ) p\_percentage IN NUMBER(\ IS\ BEGIN\ UPDATE emp\ SET salary = salary \* 1 + (p\_percentage/100);\ END;\ /\ \--استدعاء الدالة BEGIN increase\_salaries(10); \-- زيادة الرواتب بنسبة 10% END; / **7. إجراء لإيجاد أكبر راتب** CREATE OR REPLACE PROCEDURE find\_max\_salary\ IS\ v\_max\_salary NUMBER;\ BEGIN\ SELECT MAX(salary) INTO v\_max\_salary\ FROM employees;\ \ DBMS\_OUTPUT.PUT\_LINE(\'الراتب هو \'\|\| v\_max\_salary); END;\ / \--استدعاء الدالة BEGIN find\_max\_salary ; END; / **8. عرض جميع الموظفين** CREATE OR REPLACE PROCEDURE show\_all\_employees AS\ BEGIN\ DBMS\_OUTPUT.PUT\_LINE(\'EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO\');\ FOR emp\_rec IN (SELECT \* FROM emp) LOOP\ DBMS\_OUTPUT.PUT\_LINE(emp\_rec.empno \|\| \' \' \|\| emp\_rec.ename \|\| \' \' \|\| emp\_rec.job \|\| \' \' \|\|\ emp\_rec.mgr \|\| \' \' \|\| emp\_rec.hiredate \|\| \' \' \|\| emp\_rec.sal \|\| \' \' \|\|\ emp\_rec.comm \|\| \' \' \|\| emp\_rec.deptno);\ END LOOP;\ END; / \--استدعاء الدالة BEGIN show\_all\_employees; END; / **9. إجراء لإنشاء جدول جديد** CREATE OR REPLACE PROCEDURE create\_new\_table\ IS\ BEGIN\ EXECUTE IMMEDIATE \'CREATE TABLE new\_table (id NUMBER, name VARCHAR2(50))\';\ END;\ /\ \ \--استدعاء الدالة BEGIN create\_new\_table; END; / **10. إيجاد أعلى راتب في القسم 30** CREATE OR REPLACE PROCEDURE find\_max\_salary\_dept30 (max\_salary OUT NUMBER) AS\ BEGIN\ SELECT MAX(sal(INTO max\_salary FROM emp WHERE deptno:=30;\ END;\ / \--استدعاء الدالة DECLARE max\_salary number; BEGIN find\_max\_salary\_dept30(max\_salary); DBMS\_OUTPUT.PUT\_LINE(\' max\_salary = \'\|\| max\_salary); END; / **المؤشرات (Cursors)** ---------------------- ### مقدمة **المؤشر (Cursor)** في أوراكل هو عبارة عن منطقة تخزين مؤقتة في الذاكرة يتم استخدامها لاحتواء نتيجة استعلام SQL الذي يعيد أكثر من صف واحد. بمعنى آخر، هو مؤشر يتحرك على مجموعة من الصفوف الناتجة عن استعلام معين، ويسمح لك بمعالجة هذه الصفوف صفًا صفًا بدلاً من الحصول على النتيجة كاملة في وقت واحد. بمعنى ان المؤشر تسمح لك بالوصول إلى نتائج استعلام SQL بشكل صف بصف، بدلاً من الحصول على النتيجة بأكملها دفعة واحدة. هذا يمنحك مزيدًا من التحكم في كيفية معالجة البيانات المسترجعة من قاعدة البيانات. ### لماذا نستخدم المؤشرات؟ - **معالجة نتائج كبيرة:** عندما يكون حجم البيانات المسترجعة كبيرًا، فإن المؤشرات تساعد في تجنب استهلاك كمية كبيرة من الذاكرة دفعة واحدة. - **التحكم في سجلات البيانات:** يمكنك معالجة كل سجل بشكل فردي، واتخاذ قرارات بناءً على قيم السجل الحالي. - **تحديث البيانات:** يمكنك تحديث البيانات أثناء التمرير على المؤشر. - ![](media/image10.png)**العمليات المعقدة:** تستخدم المؤشرات لتنفيذ عمليات معقدة تتطلب معالجة متعددة المراحل للبيانات. ### بنية (دورة حياة) المؤشر الأساسية تتكون بنية المؤشر بشكل عام من الأجزاء التالية: ###.1 **إعلان المؤشر (Cursor Declaration):** - **تعريف الاسم:** يتم إعطاء المؤشر اسمًا فريدًا لتمييزه عن المؤشرات الأخرى. - **ربطه بالاستعلام:** يتم ربط المؤشر باستعلام SQL يحدد البيانات التي سيتم استرجاعها. - **تحديد الأعمدة:** يتم تحديد الأعمدة التي ستتم استرجاعها من الاستعلام. ###.2 **فتح المؤشر (Cursor Open):** - يتم تنفيذ الاستعلام المرتبط بالمؤشر. - يتم تحميل النتائج في منطقة تخزين مؤقت. - يتم وضع المؤشر قبل الصف الأول من النتائج. ###.3 **الوصول إلى البيانات (Fetching):** - **الأمر FETCH:** يستخدم لجلب الصف الحالي من المؤشر وتخزين قيمه في المتغيرات. - **الحلقة LOOP:** تستخدم لتكرار عملية الجلب حتى الوصول إلى نهاية النتائج. - **شرط الخروج:** يستخدم الشرط %NOTFOUND للتحقق من الوصول إلى نهاية النتائج والخروج من الحلقة. ###.4 **إغلاق المؤشر (Cursor Close):** - يتم إغلاق المؤشر لتحرير الموارد المستخدمة. 6. سمات المؤشر (Cursor Attributes): - **%NOTFOUND** تُستخدم للتحقق مما إذا تم الوصول إلى نهاية مجموعة النتائج لتعيد True خلاف ذلك تعيد False. - **%FOUND** يعود TRUE عندما يتحقق انه مازال يوجد صف حالي في المؤشر خلاف ذلك تعيد False. - **%ROWCOUNT** يعطي عدد السجلات التي تم استرجاعها حتى الآن. - **%ISOPEN** يعود TRUE إذا كان المؤشر مفتوحًا و FALSE إذا كان مغلقًا. 7. **استخدامات المؤشرات:** - **معالجة نتائج كبيرة:** معالجة البيانات صفًا بصف بدلاً من تحميلها دفعة واحدة. - **التحكم في سجلات البيانات:** معالجة كل سجل بشكل فردي واتخاذ قرارات بناءً عليه. - **تحديث البيانات:** تحديث البيانات أثناء التمرير على المؤشر. - **العمليات المعقدة:** تنفيذ عمليات معقدة تتطلب معالجة متعددة المراحل للبيانات. 8. **أنواع المؤشرات في PL/SQL** 1. **المؤشرات الضمنية (Implicit Cursors):** - **تعريف:** يتم إنشاؤها تلقائيًا عند تنفيذ أي عبارة SQL تقوم باسترجاع مجموعة من الصفوف، مثل SELECT، UPDATE، DELETE. - مثال اكتب كود sql يقوم بزيادة رواتب الموظفين بنسبة 10% (مؤشر ضمني) UPDATE employees\ SET salary = salary \* 1.1\ WHERE department\_id :=20; - مثال اكتب كود sql يقوم بزيادة رواتب الموظفين بنسبة 10% (مؤشر ضمني) BEGIN\ FOR emp\_rec IN (SELECT \* FROM emp) LOOP DBMS\_OUTPUT.PUT\_LINE(emp\_rec.ename); END LOOP; END; / - **ملاحظة** لا يمكن التحكم مباشرة في المؤشرات الضمنية، ولكن يمكن استخدام بعض الخصائص مثل %ROWCOUNT و %FOUND و %NOTFOUND للحصول على معلومات حولها. 2. **المؤشرات الصريحة (Explicit Cursors):** - **تعريف:** يتم تعريفها بشكل صريح في الكود من قبل المبرمج باستخدام الكلمة المفتاحية CURSOR، مما يمنحك تحكمًا أكبر في عملية الاسترجاع والمعالجة. ![](media/image15.png) ### الصيغة العامة للمؤشر الصريح DECLARE\ CURSOR my\_cursor IS\ SELECT \* FROM my\_table WHERE condition;\ v\_column1 my\_table.column1%TYPE;\ v\_column2 my\_table.column2%TYPE;\ \-- \... باقي الأعمدة\ BEGIN\ OPEN my\_cursor;\ LOOP\ FETCH my\_cursor INTO v\_column1, v\_column2,...;\ EXIT WHEN my\_cursor%NOTFOUND;\ \-- معالجة البيانات\ END LOOP;\ CLOSE my\_cursor;\ END;\ / ### أمثلة على استخدام المؤشرات ### 1. **طباعة جميع أسماء الموظفين** DECLARE\ CURSOR emp\_cursor IS SELECT ename FROM emp;\ v\_ename emp.ename%TYPE;\ BEGIN\ OPEN emp\_cursor;\ LOOP\ FETCH emp\_cursor INTO v\_ename;\ EXIT WHEN emp\_cursor%NOTFOUND;\ DBMS\_OUTPUT.PUT\_LINE(v\_ename);\ END LOOP;\ CLOSE emp\_cursor;\ END;\ / 2. **تحديث رواتب الموظفين الذين يقل راتبهم عن 5000 بأستخدام متغيرات من نوع type** DECLARE\ CURSOR emp\_cursor IS SELECT empno, sal FROM emp WHERE sal \< 5000;\ v\_empno emp.empno%TYPE;\ v\_sal emp.sal%TYPE;\ BEGIN\ OPEN emp\_cursor;\ LOOP\ FETCH emp\_cursor INTO v\_empno, v\_sal;\ EXIT WHEN emp\_cursor%NOTFOUND;\ UPDATE emp SET sal = sal \* 1.1 WHERE empno = v\_empno;\ END LOOP;\ COMMIT;\ CLOSE emp\_cursor;\ END;\ / **3. طباعة ارقام الموظفين واسمائهم بأستخدام متغير من نوع rowtype** DECLARE\ CURSOR emp\_cursor IS\ SELECT \* FROM emp;\ متغير من نوع صف الجدول (الموظفين) \--\ v\_emp\_rec emp%ROWTYPE;\ \ BEGIN\ OPEN emp\_cursor;\ \ LOOP\ FETCH emp\_cursor INTO v\_emp\_rec;\ EXIT WHEN emp\_cursor%NOTFOUND; DBMS\_OUTPUT.PUT\_LINE\|\|\'رقم الموظف: \') v\_emp\_rec.empno \|\| \', الاسم: \' \|\| v\_emp\_rec.ename); END LOOP;\ \ CLOSE emp\_cursor;\ END;\ / **الشرح:** - **v\_emp\_rec emp%ROWTYPE** تم تعريف متغير اسمه v\_emp\_rec من نوع emp%ROWTYPE. هذا يعني أن هذا المتغير يمكنه استيعاب جميع أعمدة الجدول emp بنفس أنواع البيانات. - **FETCH emp\_cursor INTO v\_emp\_rec;:** عند استرجاع صف من المؤشر، يتم تخزين جميع قيم الأعمدة في المتغير v\_emp\_rec مباشرة. **فوائد استخدام %ROWTYPE:** - **تبسيط الكود:** يجعل الكود أكثر قابلية للقراءة والصيانة، خاصة عند وجود عدد كبير من الأعمدة في الجدول. - **تحسين الأداء:** في بعض الحالات، قد يحسن استخدام %ROWTYPE من أداء البرنامج. - **مرونة أكبر:** يمكن استخدام المتغير من نوع %ROWTYPE في عمليات أخرى مثل التحديث والحذف. **مثال آخر مع شرط:** 4. لنفترض أننا نريد طباعة بيانات الموظفين الذين يعملون في القسم رقم 20: DECLARE\ CURSOR emp\_cursor IS\ SELECT \* FROM emp WHERE deptno := 20 ; v\_emp\_rec emp%ROWTYPE;\ BEGIN\ OPEN emp\_cursor; LOOP\ FETCH emp\_cursor INTO v\_emp\_rec;\ EXIT WHEN emp\_cursor%NOTFOUND;\ \ DBMS\_OUTPUT.PUT\_LINE(\|\|\'رقم الموظف: \' v\_emp\_rec.empno \|\| \', الاسم: \' \|\| v\_emp\_rec.ename \|\| \', القسم: \' \|\| v\_emp\_rec.deptno(;\ END LOOP;\ \ CLOSE emp\_cursor;\ END;\ / ### الخلاصة المؤشرات هي أداة قوية في PL/SQL تتيح لك التحكم الدقيق في معالجة البيانات المسترجعة من قاعدة البيانات. من خلال فهم مفهوم المؤشرات وبنيتها، يمكنك كتابة برامج PL/SQL أكثر تعقيدًا وكفاءة. 5. اكتب مؤشر لحذف سجلات في الادارة 10 من جدول EMP DECLARE CURSOR c\_emp IS SELECT empno FROM emp WHERE deptno = 10; v\_empno emp.empno%TYPE; BEGIN OPEN c\_emp; LOOP FETCH c\_emp INTO v\_empno; EXIT WHEN c\_emp%NOTFOUND; DELETE FROM emp WHERE empno = v\_empno; END LOOP; CLOSE c\_emp; COMMIT; \--لتأكيد الحذف EXCEPTION WHEN OTHERS THEN DBMS\_OUTPUT.PUT\_LINE(\'حدث خطأ: \' \|\| SQLERRM); ROLLBACK; \--لإلغاء التغييرات في حالة حدوث خطأ END; / **شرح الكود:** 1. **إعلان المؤشر:** - CURSOR c\_emp IS \...: يعلن عن مؤشر جديد باسم c\_emp والذي سيستخدم لاستعراض سجلات الموظفين في الإدارة 10. - SELECT empno FROM emp WHERE deptno = 10: هذا الاستعلام يحدد السجلات التي سيتم معالجتها بواسطة المؤشر، أي موظفي الإدارة 10. 2. **إعلان المتغير:** - v\_empno emp.empno%TYPE: يعلن عن متغير v\_empno من نفس نوع بيانات حقل empno في جدول emp لتخزين رقم الموظف المسترجع من المؤشر. 3. **فتح المؤشر:** - OPEN c\_emp: يفتح المؤشر لبدء استعراض السجلات. 4. **الحلقة:** - LOOP \... END LOOP: تبدأ حلقة تكرارية لمعالجة كل سجل. - FETCH c\_emp INTO v\_empno: تسترجع قيمة empno للسجل الحالي وتخزنها في المتغير v\_empno. - EXIT WHEN c\_emp%NOTFOUND: يتوقف التكرار عندما لا يوجد المزيد من السجلات. - DELETE FROM emp WHERE empno = v\_empno: يحذف السجل الحالي من الجدول. 5. **إغلاق المؤشر:** - CLOSE c\_emp: يغلق المؤشر بعد الانتهاء من المعالجة. 6. **التأكيد على الحذف:** - COMMIT: يؤكد التغييرات على قاعدة البيانات. 7. **معالجة الأخطاء:** - EXCEPTION \... END يعالج أي أخطاء قد تحدث أثناء تنفيذ الكود. - DBMS\_OUTPUT.PUT\_LINE(\'ERROR\' \|\| SQLERRM); - ROLLBACK يلغي جميع التغييرات التي تم إجراؤها في حالة حدوث خطأ. **القادحات (Triggers) في أوراكل** **ما هي القادحات ؟** القادحات في أوراكل هي عبارة عن وحدات برمجية يتم تنفيذها تلقائيًا استجابة لحدث معين يحدث على جدول في قاعدة البيانات. هذا الحدث يمكن أن يكون إدراج سجل جديد، أو تحديث سجل موجود، أو حذف سجل. بمعنى آخر، القادحات هي آلية لتنفيذ عمليات إضافية تلقائيًا عند حدوث تغييرات معينة على البيانات. **لماذا نستخدم القادحات؟** - **تنفيذ عمليات تلقائية:** يمكن استخدام القادحات لأتمتة مهام مثل: - حساب قيم الحقول تلقائيًا (مثل تاريخ التعديل) او ادخال قيم معرفات الجداول مثل رقم الموظف او الطالب الخ. - إرسال إشعارات عند حدوث تغييرات معينة. - تنفيذ عمليات تدقيق على البيانات من حيث التأكد هل تتوافق مع قيود معينة تم وضعها مسبقا. - الحفاظ على سلامة البيانات حيث تمنع الوصول او الكتابة على بيانات ليست ضمن الصلاحيات المتاحة للمستخدمين. - **تطبيق قواعد الأعمال:** يمكن استخدام القادحات لفرض قواعد الأعمال على البيانات. - **سجل التغييرات:** يمكن استخدام القادحات لتسجيل التغييرات التي تحدث على البيانات. **أنواع القادحات** - **قبل الإدراج (BEFORE INSERT):** يتم تنفيذ هذا النوع من القادحات قبل إضافة سجل جديد إلى الجدول. - **بعد الإدراج (AFTER INSERT):** يتم تنفيذ هذا النوع من القادحات بعد إضافة سجل جديد إلى الجدول. - **قبل التحديث (BEFORE UPDATE):** يتم تنفيذ هذا النوع من القادحات قبل تحديث سجل موجود في الجدول. - **بعد التحديث (AFTER UPDATE):** يتم تنفيذ هذا النوع من القادحات بعد تحديث سجل موجود في الجدول. - **قبل الحذف (BEFORE DELETE):** يتم تنفيذ هذا النوع من القادحات قبل حذف سجل من الجدول. - **بعد الحذف (AFTER DELETE):** يتم تنفيذ هذا النوع من القادحات بعد حذف سجل من الجدول. **بنية القادح** CREATE OR REPLACE TRIGGER trigger\_name\ BEFORE \| AFTER INSERT OR UPDATE OR DELETE ON table\_name\ FOR EACH ROW\ BEGIN\ \-- تعليمات القادح هنا\ END;\ / **أمثلة على القادحات** **1. التحقق من صحة البيانات المدخلة** CREATE OR REPLACE TRIGGER validate\_salary\ BEFORE INSERT OR UPDATE ON emp\ FOR EACH ROW\ BEGIN\ IF :new.sal \ 2. **إنشاء الـTrigger:** CREATE OR REPLACE TRIGGER TRG\_EMP\_DELETE\ BEFORE DELETE ON EMP\ FOR EACH ROW\ BEGIN\ INSERT INTO ARCHIVE\_EMP\ ) empno, ename, job, mgr, hiredate, sal, comm, deptno, archive\_date(\ VALUES\ ):OLD.empno, :OLD.ename, :OLD.job, :OLD.mgr, :OLD.hiredate, ::OLD.sal, :OLD.comm, :OLD.deptno, SYSDATE);\ END;\ / **شرح الـTrigger:** - **BEFORE DELETE ON EMP:** يشير إلى أن الـTrigger سينفذ قبل عملية الحذف على جدول EMP. - **FOR EACH ROW:** يعني أن الـTrigger سينفذ لكل صف يتم حذفه. - **:OLD:** يشير إلى قيم الصف قبل الحذف. - **INSERT INTO ARCHIVE\_EMP:** يقوم بإدراج بيانات الصف المحذوف في جدول الأرشفة. - **SYSDATE:** يسجل تاريخ الأرشفة الحالي. **كيفية عمل الـTrigger:** عندما تحاول حذف سجل من جدول EMP، سيقوم الـTrigger تلقائيًا بنسخ بيانات هذا السجل إلى جدول ARCHIVE\_EMP قبل حذفه من الجدول الأصلي. بذلك، يتم الاحتفاظ بنسخة أرشيفية للبيانات المحذوفة، ويمكن الرجوع إليها في أي وقت إذا لزم الأمر. **المزايا:** - **الحفاظ على سجل تاريخي:** يساعد في تتبع التغييرات التي طرأت على البيانات. - **استعادة البيانات:** يمكن استعادة البيانات المحذوفة من جدول الأرشفة إذا لزم الأمر. - **تحليل البيانات:** يمكن استخدام البيانات في جدول الأرشفة لتحليل الاتجاهات والأنماط. - **الامتثال للوائح:** قد تتطلب بعض اللوائح الاحتفاظ بسجلات للبيانات المحذوفة. **ملاحظات:** - يمكنك تخصيص جدول الأرشفة بإضافة أعمدة إضافية مثل سبب الحذف أو اسم المستخدم الذي قام بالحذف. - يمكن استخدام هذا المفهوم لإنشاء جداول أرشفة لأي جدول آخر في قاعدتك البيانات. - تأكد من أن لديك الصلاحيات اللازمة لإنشاء جداول وTriggers في قاعدة البيانات. - قد يؤثر هذا الـTrigger على أداء قاعدة البيانات، خاصة إذا كان هناك عدد كبير من عمليات الحذف. **مثال على استخدام الـTrigger:** DELETE FROM emp WHERE empno = 100; عند تنفيذ هذا الأمر، سيتم أولاً نسخ بيانات الموظف برقم 100 إلى جدول ARCHIVE\_EMP، ثم يتم حذف السجل من جدول EMP. **10. تحديث تاريخ آخر تسجيل دخول للمستخدم** CREATE OR REPLACE TRIGGER update\_last\_login\ AFTER LOGON ON SCHEMA\ BEGIN\ UPDATE users\ SET last\_login = SYSDATE\ WHERE user\_id = USER;\ END;\ / - **الشرح:** يقوم هذا القادح بتحديث حقل last\_login في جدول المستخدمين عند تسجيل دخول المستخدم. **ملاحظات هامة:** - **:NEW و :OLD:** هاتان القيمتان تمثلان الصف الجديد والصف القديم على التوالي. - **FOR EACH ROW:** يعني أن القادح سيتم تنفيذه لكل صف متأثر بالحدث. - **RAISE\_APPLICATION\_ERROR:** تستخدم لإثارة استثناء مخصص. - **UTL\_MAIL:** حزمة في أوراكل تستخدم لإرسال رسائل البريد الإلكتروني. **الاستخدام الحذر:** يجب استخدام القادحات بحذر وتخطيط جيد لتجنب التأثير السلبي على أداء قاعدة البيانات. **الحزم (Packages)** **ما هي الحزمة؟** الحزمة في أوراكل هي عبارة عن وحدة برمجية تجمع مجموعة من العناصر المتعلقة ببعضها البعض مثل: - **الأنواع:** تعريف أنواع بيانات مخصصة (السجلات). - **المتغيرات:** تخزين قيم يمكن استخدامها داخل الحزمة. - **الاستثناءات:** التعامل مع الأخطاء. - **الدوال:** تنفيذ عمليات حسابية أو منطقية او تنفيذ الاستعلامات وإرجاع قيمة. - **الإجراءات:** تنفيذ سلسلة من الأوامر ولا ترجع قيمة. - **المؤشرات:** للتعامل مع مجموعات من البيانات. **لماذا نستخدم الحزم؟** - **التنظيم:** تجمع الحزم عناصر ذات صلة ببعضها في وحدة واحدة، مما يسهل الصيانة وإعادة الاستخدام. - **إخفاء التفاصيل:** يمكن إخفاء تفاصيل تنفيذ الوظائف والإجراءات عن المستخدم، مما يزيد من قابلية الصيانة. - **الأمان:** يمكن تحديد مستوى الوصول إلى العناصر الموجودة داخل الحزمة. - **الكفاءة:** يمكن تحسين أداء التطبيقات عن طريق تخزين الحزم في الذاكرة التخزينية. **أجزاء الحزمة:** - **التعريف (Specification):** يحدد واجهة الحزمة، أي العناصر التي يمكن الوصول إليها من خارج الحزمة. - **الجسم (Body):** يحتوي على تنفيذ العناصر المحددة في التعريف. **مثال 1: إنشاء حزمة بسيطة** \--قسم التصريح CREATE OR REPLACE PACKAGE my\_package IS\ PROCEDURE say\_hello;\ END my\_package; \--قسم تعريف الحزمة (جسم الحزمة) CREATE OR REPLACE PACKAGE BODY my\_package IS\ PROCEDURE say\_hello IS\ BEGIN\ DBMS\_OUTPUT.PUT\_LINE(\'Hello, World\');\ END;\ END my\_package; **مثال 2: حزمة لعمليات حسابية** CREATE OR REPLACE PACKAGE math\_package IS\ FUNCTION add\_numbers(x NUMBER, y NUMBER) RETURN NUMBER;\ FUNCTION subtract\_numbers(x NUMBER, y NUMBER) RETURN NUMBER;\ END math\_package;\ \ CREATE OR REPLACE PACKAGE BODY math\_package IS\ FUNCTION add\_numbers(x NUMBER, y NUMBER) RETURN NUMBER IS\ BEGIN RETURN x + y;\ END;\ \ FUNCTION subtract\_numbers(x NUMBER, y NUMBER) RETURN NUMBER IS\ BEGIN\ RETURN x - y;\ END;\ END math\_package; **مثال 3: حزمة لإدارة المستخدمين** CREATE OR REPLACE PACKAGE user\_management IS\ PROCEDURE create\_user(p\_username VARCHAR2, p\_password VARCHAR2);\ PROCEDURE delete\_user(p\_username VARCHAR2);\ END user\_management;\ \ CREATE OR REPLACE PACKAGE BODY user\_management IS\ PROCEDURE create\_user(p\_username VARCHAR2, p\_password VARCHAR2) IS\ BEGIN\ INSERT INTO users (username, password)\ VALUES )p\_username, p\_password( ;\ EXCEPTION\ WHEN DUP\_VAL\_ON\_INDEX THEN\ DBMS\_OUTPUT.PUT\_LINE(\'Username already exists \' ;\ END;\ \ PROCEDURE delete\_user(p\_username VARCHAR2) IS\ BEGIN\ DELETE FROM users\ WHERE username = p\_username;\ EXCEPTION\ WHEN NO\_DATA\_FOUND THEN\ DBMS\_OUTPUT.PUT\_LINE(\'User not found.\');\ END;\ END user\_management; **الشرح:** - **إضافة فحص للتكرار:** تم إضافة استثناء DUP\_VAL\_ON\_INDEX للتعامل مع حالة وجود اسم مستخدم مكرر، بافتراض أن هناك مؤشر فريد على حقل username. - **إضافة استثناء للعدم وجود البيانات:** تم إضافة استثناء NO\_DATA\_FOUND للتعامل مع حالة عدم وجود المستخدم المراد حذفه. **مثال 4: حزمة مع مؤشر** CREATE OR REPLACE PACKAGE emp\_package IS\ TYPE emp\_rec IS RECORD )\ empno NUMBER,\ ename VARCHAR2(10)\ (;\ CURSOR get\_employees RETURN emp\_rec;\ END emp\_package; **مثال 5: حزمة مع استثناء** CREATE OR REPLACE PACKAGE my\_package IS\ user\_not\_found EXCEPTION;\ PROCEDURE delete\_user(p\_username VARCHAR2);\ END my\_package;\ \ \-- \... جسم الحزمة CREATE OR REPLACE PACKAGE BODY emp\_package IS\ CURSOR get\_employees RETURN emp\_rec IS\ SELECT empno, ename\ FROM emp;\ END emp\_package; **الشرح:** - هذا الجسم بسيط جدًا حيث يقوم بتعريف المؤشر get\_employees الذي يعيد سجلًا من نوع emp\_rec يحتوي على رقم الموظف واسم الموظف. **ملاحظات:** - يمكن استدعاء العناصر الموجودة داخل الحزمة باستخدام اسم الحزمة ونقطة. - يمكن للحزم أن تحتوي على حزم أخرى. - يمكن استخدام الحزم لإنشاء مكتبات من الوظائف والإجراءات القابلة لإعادة الاستخدام. **فوائد استخدام الحزم:** - **تنظيم الكود:** تجعل الكود أكثر قابلية للقراءة والصيانة. - **إعادة الاستخدام:** يمكن إعادة استخدام العناصر الموجودة داخل الحزمة في تطبيقات مختلفة. - **الأمن:** يمكن التحكم في الوصول إلى العناصر الموجودة داخل الحزمة. - **الأداء:** يمكن تحسين أداء التطبيقات عن طريق تخزين الحزم في الذاكرة التخزينية. **الحزم (Packages)** الاستثناءات (Exceptions) في Oracle 10g تُستخدم للتعامل مع الأخطاء التي قد تحدث أثناء تنفيذ كود PL/SQL. تسمح لك الاستثناءات بالتحكم في تدفق البرنامج عند حدوث أخطاء، وإجراء إجراءات تصحيحية أو إظهار رسائل خطأ مفيدة. **أنواع الاستثناءات** **1. الاستثناءات المحددة مسبقًا (Predefined Exceptions):** \- هي استثناءات معرّفة مسبقًا في Oracle، وتحدث عند حدوث أخطاء معروفة مثل قسمة على صفر أو انتهاك القيود. \- أمثلة: \- \`**NO\_DATA\_FOUND**\`: يحدث عند عدم العثور على أي بيانات في استعلام \`SELECT INTO\`. \- \`**TOO\_MANY\_ROWS**\`: يحدث عند استرجاع أكثر من صف واحد في استعلام \`SELECT INTO\`. \- \`**ZERO\_DIVIDE**\`: يحدث عند محاولة القسمة على صفر. \- **\'OTHERS\'** : يحدث عند وجود خطأ غير متوقع. \- \`**DUP\_VAL\_ON\_INDEX**\`: يحدث عند محاولة إدراج قيمة مكررة في عمود مفهرس بشكل فريد. **2. الاستثناءات غير المحددة (User-Defined Exceptions):** \- هي استثناءات يحددها المطور لتلبية احتياجات التطبيق. \- يتم تعريفها باستخدام \`EXCEPTION\` ويتم رفعها يدويًا باستخدام \`RAISE\`. **3. الاستثناءات غير المعالجة (Unhandled Exceptions):** \- هي أخطاء غير متوقعة ولا يتم التعامل معها في كود PL/SQL، مما يؤدي إلى إنهاء البرنامج. **بنية معالجة الاستثناءات:** DECLARE \-- تعريف المتغيرات والاستثناءات BEGIN \-- الكود الرئيسي EXCEPTION WHEN exception1 THEN \-- معالجة الاستثناء الأول WHEN exception2 THEN \-- معالجة الاستثناء الثاني WHEN OTHERS THEN \-- معالجة أي استثناء آخر END; **أمثلة توضيحية:** **1. مثال على \`NO\_DATA\_FOUND\`:** DECLARE v\_emp\_name EMP.ENAME%TYPE; BEGIN \-- محاولة استرجاع اسم موظف برقم غير موجود\-- SELECT ENAME INTO v\_emp\_name FROM EMP WHERE EMPNO = 9999; DBMS\_OUTPUT.PUT\_LINE\|\|\'اسم الموظف: \' )v\_emp\_name); EXCEPTION WHEN NO\_DATA\_FOUND THEN DBMS\_OUTPUT.PUT\_LINE(\'لم يتم العثور على الموظف.\'); WHEN OTHERS THEN DBMS\_OUTPUT.PUT\_LINE\'حدث خطأ غير متوقع: \') \|\|SQLERRM); END;/ \- النتيجة : سيتم طباعة \"لم يتم العثور على الموظف.\" لأن الرقم 9999 غير موجود في الجدول. **2. مثال على \`TOO\_MANY\_ROWS\`:** DECLARE v\_emp\_name EMP.ENAME%TYPE; BEGIN \-- محاولة استرجاع اسم موظف بدون تحديد رقم موظف\-- SELECT ENAME INTO v\_emp\_name FROM EMP; DBMS\_OUTPUT.PUT\_LINE \'اسم الموظف: \' ) \|\|v\_emp\_name); EXCEPTION WHEN TOO\_MANY\_ROWS THEN DBMS\_OUTPUT.PUT\_LINE(\'تم استرجاع أكثر من صف واحد.\'); WHEN OTHERS THEN DBMS\_OUTPUT.PUT\_LINE\|\| \'حدث خطأ غير متوقع: \') SQLERRM); END; \- النتيجة : سيتم طباعة \"تم استرجاع أكثر من صف واحد.\" لأن الاستعلام يعيد أكثر من صف. **3. مثال على \`ZERO\_DIVIDE\`:** DECLARE v\_result NUMBER; BEGIN \-- محاولة القسمة على صفر\-- v\_result := 10 / 0; DBMS\_OUTPUT.PUT\_LINE(\'النتيجة: \' ) \|\|v\_result); EXCEPTION WHEN ZERO\_DIVIDE THEN DBMS\_OUTPUT.PUT\_LINE(\'لا يمكن القسمة على صفر.\'); WHEN OTHERS THEN DBMS\_OUTPUT.PUT\_LINE \|\|\'حدث خطأ غير متوقع: \') SQLERRM); END; \- النتيجة : سيتم طباعة \"لا يمكن القسمة على صفر.\" لأن القسمة على صفر غير مسموحة. **4. مثال على \`DUP\_VAL\_ON\_INDEX\`:** BEGIN \-- محاولة إدراج قيمة مكررة في عمود مفهرس بشكل فريد\-- INSERT INTO EMP (EMPNO, ENAME) VALUES (7369, \'John\'); EXCEPTION WHEN DUP\_VAL\_ON\_INDEX THEN DBMS\_OUTPUT.PUT\_LINE(\'تمت محاولة إدراج قيمة مكررة.\'); WHEN OTHERS THEN DBMS\_OUTPUT.PUT\_LINE \|\|\'حدث خطأ غير متوقع: \' ) SQLERRM); END; \- النتيجة : سيتم طباعة \"تمت محاولة إدراج قيمة مكررة.\" إذا كان الرقم 7369 موجودًا بالفعل. **5. مثال على استثناء مخصص (User-Defined Exception):** DECLARE v\_salary EMP.SAL%TYPE; salary\_too\_low EXCEPTION; BEGIN \-- استرجاع راتب موظف\-- SELECT SAL INTO v\_salary FROM EMP WHERE EMPNO = 7369; \-- التحقق من أن الراتب أقل من 1000 IF v\_salary \< 1000 THEN RAISE salary\_too\_low; END IF; DBMS\_OUTPUT.PUT\_LINE \|\|\'الراتب: \' ) v\_salary); EXCEPTION WHEN salary\_too\_low THEN DBMS\_OUTPUT.PUT\_LINE(\'الراتب أقل من الحد الأدنى.\'); WHEN OTHERS THEN DBMS\_OUTPUT.PUT\_LINE\'حدث خطأ غير متوقع: \') \|\|QLERRM); END; \- النتيجة : إذا كان راتب الموظف أقل من 1000، سيتم طباعة \"الراتب أقل من الحد الأدنى.\" كيفية استخدام \`SQLCODE\` و \`SQLERRM\`: \- \`SQLCODE\`: يعرض رمز الخطأ. \- \`SQLERRM\`: يعرض رسالة الخطأ. **Oracle Builder 10g** هو أداة تطوير متكاملة تعتبر جزءًا من مجموعة Oracle Developer Suite، والتي تم تصميمها لمساعدة المطورين على بناء تطبيقات قواعد البيانات بشكل سريع وفعال. تم إطلاقه في أوائل العقد الأول من القرن الحادي والعشرين، وكان يستهدف بشكل رئيسي تطوير تطبيقات الويب وقواعد البيانات باستخدام تقنيات Oracle. المكونات الرئيسية لـ Oracle Builder 10g: **1. واجهة المستخدم الرسومية (GUI) :** \- توفر واجهة مستخدم سهلة الاستخدام تسمح للمطورين بإنشاء وتعديل التطبيقات بشكل مرئي دون الحاجة إلى كتابة الكثير من الأكواد يدويًا. **2. محرر النماذج (Forms Builder) :** \- أداة لإنشاء نماذج تفاعلية تعتمد على البيانات المخزنة في قواعد بيانات Oracle. تسمح للمطورين بإنشاء واجهات مستخدم غنية لتطبيقات قواعد البيانات. **3. محرر التقارير (Reports Builder) :** \- أداة لتصميم وإنشاء تقارير معقدة تعتمد على بيانات Oracle. تدعم مجموعة واسعة من تنسيقات الإخراج مثل PDF، HTML، وغيرها. **4. محرر الرسومات (Graphics Builder) :** \- أداة لإنشاء رسومات بيانية ورسوم توضيحية تعتمد على البيانات المخزنة في قواعد بيانات Oracle. **5. محرر الاستعلامات (Query Builder) :** \- أداة تسمح للمطورين بإنشاء وتنفيذ استعلامات SQL بشكل مرئي، مما يسهل عملية استرجاع البيانات من قواعد البيانات. **6. إدارة المشاريع (Project Management) :** \- يوفر أدوات لإدارة المشاريع والتطبيقات، مما يسمح للمطورين بتنظيم العمل بشكل أفضل. **7. التكامل مع Oracle Database :** \- يتميز Oracle Builder 10g بتكامل قوي مع قواعد بيانات Oracle، مما يسمح بإنشاء تطبيقات تعمل بشكل سلس مع البيانات المخزنة في Oracle. **8. دعم تطبيقات الويب :** \- يدعم إنشاء تطبيقات ويب تفاعلية تعمل مع قواعد بيانات Oracle، مما يجعله أداة قوية لتطوير تطبيقات الويب. **9. أدوات التصحيح والاختبار :** \- يوفر أدوات مدمجة لتصحيح الأخطاء واختبار التطبيقات لضمان جودتها وسلامتها قبل نشرها. باختصار، Oracle Builder 10g أداة قوية لتطوير تطبيقات قواعد البيانات والتقارير، خاصة في البيئات التي تعتمد على Oracle Database. **Object Navigator (مستكشف الكائنات)** يعتبر Object Navigator (مستكشف الكائنات) أحد المكونات الأساسية في واجهة التطوير. يتم استخدامه لتنظيم وإدارة جميع الكائنات والمكونات التي يتم العمل عليها ضمن المشروع، مثل النماذج (Forms)، التقارير (Reports)، الرسومات (Graphics)، وغيرها. يوفر Object Navigator طريقة هرمية لعرض الكائنات وتحريرها، مما يسهل على المطورين التنقل بين العناصر المختلفة وإدارتها. المكونات الرئيسية لـ Object Navigator في Oracle Builder 10g: **1. عرض هرمي للكائنات :** \- يعرض Object Navigator الكائنات في شكل شجرة (Tree Structure)، مما يسمح للمطورين بالتنقل بسهولة بين العناصر المختلفة مثل النماذج، التقارير، القوائم، المكتبات، وغيرها. \- يتم تنظيم الكائنات بشكل منطقي، مما يسهل الوصول إلى أي عنصر بسرعة. **2. أنواع** **الكائنات** **المدعومة** : **- النماذج (Forms)** : يحتوي على النماذج التي تم إنشاؤها باستخدام Forms Builder. **- التقارير (Reports)** : يحتوي على التقارير التي تم إنشاؤها باستخدام Reports Builder. **- الرسومات (Graphics**) : يحتوي على الرسومات البيانية التي تم إنشاؤها باستخدام Graphics Builder. **- القوائم (Menus)** : يحتوي على القوائم التي تم إنشاؤها لتطبيقات Oracle. **- المكتبات (Libraries)** : يحتوي على مكتبات PL/SQL أو عناصر قابلة لإعادة الاستخدام. **- الكائنات الأخرى** : مثل الجداول، الاستعلامات، الإجراءات، والمزيد. **3. إدارة الكائنات :** **- إنشاء كائنات جديدة** : يمكن إنشاء كائنات جديدة مباشرة من خلال Object Navigator. **- تعديل الكائنات** : يمكن فتح الكائنات وتعديلها بالنقر المزدوج عليها. **- حذف الكائنات** : يمكن حذف الكائنات غير المرغوب فيها بسهولة. **- نسخ ولصق الكائنات** : يدعم نسخ الكائنات ولصقها في مواقع أخرى. **4. التنظيم والتصفية :** \- يمكن تصفية (فلترة) الكائنات المعروضة حسب النوع (مثل النماذج فقط أو التقارير فقط). \- يمكن توسيع أو طي أقسام الشجرة للتركيز على أجزاء محددة من المشروع. **5. الوصول السريع إلى الخصائص :** \- يوفر Object Navigator وصولاً سريعًا إلى خصائص الكائنات (Properties) من خلال قائمة السياق (Right-Click Menu). \- يمكن تعديل خصائص الكائنات مباشرة من خلال النافذة. **6. التكامل مع أدوات التطوير الأخرى :** \- يتكامل Object Navigator مع أدوات أخرى مثل Forms Builder وReports Builder، مما يسمح بفتح الكائنات وتحريرها مباشرة من خلال النقر عليها. **فوائد استخدام Object Navigator:** **- تنظيم المشروع** : يساعد في تنظيم جميع الكائنات بشكل هرمي، مما يسهل إدارة المشاريع الكبيرة. **- تنقل سريع** : يوفر طريقة سريعة للوصول إلى أي كائن في المشروع. **- إدارة مركزية** : يعتبر نقطة مركزية لإدارة جميع الكائنات والمكونات. **- سهولة التعديل** : يمكن تعديل الكائنات وإدارتها بسهولة من خلال واجهة واحدة. **[مجموعة أدوات المطور 10g - Developer 10g suite]** تتكون من ثلاثة مكونات **نماذج اوراكل - Oracle Forms** تستخدم لتطوير شاشات تطبيقات سهلة الاستخدام لمعالجة البيانات واسترجاعها. **تقارير اوراكل - Oracle Reports** تستخدم لتمثيل المعلومات لغرض القراءة فقط بتنسيق سهل الاستخدام. **رسومات اوراكل - Oracle Graphics** تستخدم لتمثيل المعلومات في تنسيق char بإحداثيات X وY. **[نماذج اوراكل 10جي - Forms 10g]** تدعم معالجة البيانات أو استرداد البيانات المتوفرة في RDBMS. الواجهات في النماذج - Interfaces in forms 1. مستكشف الكائنات (F3) - Object Navigator ( F3 ) يتيح إنشاء المكونات والتنقل بين شاشات النماذج الأخرى. 2. محرر التخطيط (F2) - Layout Editor ( F2 ) يستخدم لتصميم شاشات التطبيق. يدعم إنشاء عناصر التحكم (عناصر التحكم في واجهة المستخدم الرسومية). 3. لوحة الخصائص (F4) - Property pallet ( F4 ) يستخدم لتعيين خصائص عناصر التحكم. 4. محرر PL/SQL (F11) - PL/SQL Editor ( F11 ) يستخدم لتوفير التعليمات البرمجية للإجراءات، والوظائف، والحزم والمشغلات. 5. محرر القائمة - Menu Editor يستخدم لتصميم القوائم. 6. المعالجات - Wizards يستخدم لإنشاء مكونات مثل الكتل واللوحة القماشية والرسوم البيانية وقائمة القيم. مكونات النماذج - Form Components هناك مكونان مهمان للنماذج. 1. الكتل - Blocks تمثل مجموعة من عناصر التحكم (العناصر). هناك نوعان من الكتل - **كتلة الجدول الأساسي Base table block** كتلة تم إنشاؤها بناءً على جدول أو عرض أو مرادف أو إجراء مخزن. - **كتلة التحكم Control block** كتلة تم إنشاؤها بدون أي جدول. لن يمثل أي جدول. يتم إنشاء كتل التحكم يدويًا. 2. البساط Canvas تستخدم لحمل عناصر الكتلة. وهي عبارة عن حاوية يمكنها حمل أكثر من كتلة عليها. يمكن إنشاء Canvas من خلال معالج التخطيط أو يدويًا. ملاحظة النوع الافتراضي لـ Canvas هو Content Canvas. النوع الافتراضي للعنصر هو Text Item. عنصر نص (Text Item): هو عنصر تحكم قابل للتحرير، يستخدم لتمثيل عمود في جدول. يجب أن يكون هناك على الأقل Content Canvas أو Tab Canvas لتشغيل التطبيق. يجب أن يكون هناك على الأقل عنصر قابل للتحرير على سبيل المثال (Text Item) لتشغيل التطبيق. كلما تم إنشاء كتلة جدول أساسية في نموذج، فإنها تقوم تلقائيًا بتأطير عبارات الإدراج والتحديث والحذف والتحديد الداخلية. **مفاتيح الاختصار** CTRL + S : احفظ ملف FMB CTRL + T : يجمع ملف FMB ويعطي ملف FMX CTRL + R : يشغل ملف FMX (يعطي الناتج النهائي) CTRL + L : لإظهار قائمة القيم (LOVS) F2 : لفتح نافذة محرر التخطيط (التنسيقات) LAYOUT EDITOR F3: لفتح نافذة مستكشف الكائنات (OBJECT NAVIGATOR) F4 : لفتح نافذة لوحة الخصائص (PROPERTY PALETTE) F8 : تنفيذ الاستعلام (يستخدم لاسترداد البيانات من الجدول)\ F11 : لفتح نافذة محرر الشفرات PL/SQL **المعالجات Wizards** **تستخدم المعالجات لتنفيذ مهام معينة بغرض اختصار الوقت والسهولة.** **أنواعها :** - معالج كتلة البيانات (Data block wizard) \-- يستخدم لإنشاء كتلة البيانات. - معالج التخطيط (Layout wizard)\-- يستخدم لإنشاء Canvas. - معالج (LOV wizard)LOV \-- يستخدم لإنشاء قائمة بالقيم - معالج المخطط (Chart wizard)\-- يستخدم لإنشاء المخطط. - معالج التقارير (Report wizard)\-- يستخدم لإنشاء المعالج. **Property Palette لوحة الخصائص** تُعتبر Property Palette (لوحة الخصائص) واحدة من الأدوات الأساسية التي تتيح للمطورين تعديل خصائص الكائنات (Objects) في النموذج (Form)، كتلة البيانات (Block)، أو العناصر (Items). تُستخدم Property Palette لتخصيص سلوك ومظهر الكائنات بشكل ديناميكي. **أهم خصائص Property Palette في Oracle Builder 10g:** 1\. الوصول إلى Property Palette: \- يمكن الوصول إلى Property Palette عن طريق النقر بزر الماوس الأيمن على أي كائن في النموذج واختيار \"Property Palette\". \- يمكن أيضًا الوصول إليها من خلال قائمة Tools -\ Property Palette 2\. خصائص عامة (General Properties): \- Name : اسم الكائن، ويستخدم للإشارة إليه في الأكواد. \- Title : العنوان الذي يظهر للكائن (مثل عنوان النموذج أو النافذة). \- Prompt : النص الذي يظهر كتسمية بجانب العنصر (مثل Text Item). 3\. خصائص البيانات (Data Properties): \- Data Type : نوع البيانات التي يمكن إدخالها أو عرضها (مثل النصوص، الأرقام، التواريخ). \- Maximum Length : الحد الأقصى لعدد الأحرف المسموح بإدخالها. \- Default Value : القيمة الافتراضية التي تظهر عند تحميل النموذج. \- List of Values (LOV) : يمكن ربط العنصر بقائمة قيم (LOV). 4\. خصائص التنسيق (Formatting Properties): \- Font : نوع الخط وحجمه ولونه. \- Background Color : لون خلفية العنصر. \- Foreground Color : لون النص. \- Alignment : محاذاة النص داخل العنصر (يمين، يسار، وسط). 5\. خصائص الأحداث (Event Properties): \- Trigger : يمكن ربط الأحداث (مثل النقر أو تغيير القيمة) بأكواد PL/SQL. \- When-Validate-Item : يتم تنفيذه عند التحقق من صحة العنصر. \- When-Button-Pressed : يتم تنفيذه عند النقر على زر. 6\. خصائص التنقل (Navigation Properties): \- Next Navigation Item : يحدد العنصر التالي عند التنقل بين العناصر. \- Previous Navigation Item : يحدد العنصر السابق عند التنقل بين العناصر. 7\. خصائص الأمان (Security Properties): \- Enabled : يحدد ما إذا كان العنصر نشطًا وقابلًا للتفاعل. \- Insert Allowed : يحدد ما إذا كان يُسمح بإدخال بيانات جديدة في العنصر. \- Update Allowed : يحدد ما إذا كان يُسمح بتحديث البيانات الموجودة في العنصر. 8\. خصائص الأداء (Performance Properties): \- Query Array Size : عدد الصفوف التي يتم استردادها في كل مرة عند تنفيذ استعلام. \- Prefetch : يحدد عدد الصفوف التي يتم جلبها مسبقًا لتحسين الأداء. 9\. خصائص القوائم (Menu Properties): \- Menu Module : يحدد القائمة المرتبطة بالنموذج. \- Menu Item : يحدد عنصر القائمة الذي يتم تنفيذه عند النقر. 10\. خصائص النوافذ (Window Properties): \- Width and Height : تحديد حجم النافذة. \- X and Y Position : تحديد موقع النافذة على الشاشة. \- Title : عنوان النافذة. أمثلة على استخدام Property Palette: 1\. تخصيص Text Item: \- Name : \`EMP\_NAME\` \- Data Type : \`VARCHAR2\` \- Maximum Length : \`50\` \- Prompt : \`Employee Name\` \- Font : \`Arial, 12pt, Bold\` \- Background Color : \`Yellow\` 2\. تخ?