إنشاء إجراء مخزن SQL كيفية كتابة الإجراءات المخزنة بشكل صحيح في SQL Server

19.06.2020

SQL - الدرس 15. الإجراءات المخزنة. الجزء 1.

كقاعدة عامة، عند العمل مع قاعدة بيانات، نستخدم نفس الاستعلامات، أو مجموعة من الاستعلامات المتسلسلة. تسمح لك الإجراءات المخزنة بدمج سلسلة من الاستعلامات وتخزينها على الخادم. هذه أداة مريحة للغاية، والآن ستراها. لنبدأ مع بناء الجملة:

إنشاء الإجراء اسم الإجراء (المعلمات) بداية نهاية البيانات

المعلمات هي البيانات التي سنمررها إلى الإجراء عند استدعائها، والمشغلون هم الطلبات نفسها. لنكتب الإجراء الأول ونتأكد من أنه مناسب. في الدرس 10، عندما أضفنا سجلات جديدة إلى قاعدة بيانات المتجر، استخدمنا استعلامًا قياسيًا لإضافة النموذج:

أدخل في قيمة العملاء (الاسم والبريد الإلكتروني) ("إيفانوف سيرجي"، " [البريد الإلكتروني محمي]");

لأن سنستخدم طلبًا مشابهًا في كل مرة نحتاج فيها إلى إضافة عميل جديد، لذلك من المناسب تمامًا إضفاء الطابع الرسمي عليه في شكل إجراء:

إنشاء إجراء ins_cust(n CHAR(50), e CHAR(50)) البدء في إدراج قيمة العملاء (الاسم والبريد الإلكتروني) (n, e); نهاية

انتبه إلى كيفية تحديد المعلمات: تحتاج إلى إعطاء اسم للمعلمة والإشارة إلى نوعها، وفي نص الإجراء نستخدم بالفعل أسماء المعلمات. تحذير واحد. وكما تتذكر فإن الفاصلة المنقوطة تعني نهاية الطلب وإرساله للتنفيذ، وهو أمر غير مقبول في هذه الحالة. لذلك، قبل كتابة الإجراء، تحتاج إلى إعادة تعريف الفاصل c؛ إلى "//" حتى لا يتم إرسال الطلب في وقت مبكر. ويتم ذلك باستخدام عامل التشغيل DELIMITER //:

وبالتالي، أوضحنا لنظام إدارة قواعد البيانات (DBMS) أنه يجب الآن تنفيذ الأوامر بعد //. يجب أن نتذكر أن إعادة تعريف الفاصل تتم لجلسة واحدة فقط، أي. في المرة التالية التي تعمل فيها مع MySql، سيصبح الفاصل مرة أخرى فاصلة منقوطة، وإذا لزم الأمر، سيتعين إعادة تعريفه مرة أخرى. الآن يمكنك وضع الإجراء:

إنشاء إجراء ins_cust(n CHAR(50), e CHAR(50)) البدء في إدراج قيمة العملاء (الاسم والبريد الإلكتروني) (n, e); نهاية //


لذلك، تم إنشاء الإجراء. الآن، عندما نحتاج إلى إدخال عميل جديد، نحتاج فقط إلى الاتصال به، وتحديد المعلمات الضرورية. لاستدعاء إجراء مخزن، استخدم عبارة CALL، متبوعة باسم الإجراء ومعلماته. لنقم بإضافة عميل جديد إلى جدول العملاء:

اتصل بـ ins_cust("سيشوف فاليري"، " [البريد الإلكتروني محمي]")//


توافق على أن هذا أسهل بكثير من كتابة طلب كامل في كل مرة. دعونا نتحقق مما إذا كان الإجراء يعمل من خلال البحث لمعرفة ما إذا كان العميل الجديد قد ظهر في جدول العملاء:

ظهر الإجراء ويعمل وسيعمل دائمًا حتى نحذفه باستخدام عامل التشغيل إجراء إسقاط الإجراء_name.

كما ذكرنا في بداية الدرس، تسمح لك الإجراءات بدمج سلسلة من الاستعلامات. دعونا نرى كيف يتم ذلك. هل تتذكر في الدرس 11 أننا أردنا أن نعرف المبلغ الذي جلبه لنا المورد "دار الطباعة" من البضائع؟ للقيام بذلك، كان علينا استخدام الاستعلامات الفرعية والصلات والأعمدة المحسوبة وطرق العرض. ماذا لو أردنا أن نعرف المبلغ الذي جلبه لنا المورد الآخر من البضائع؟ سيتعين عليك إنشاء استعلامات وانضمامات جديدة وما إلى ذلك. من الأسهل كتابة إجراء مخزن لهذا الإجراء مرة واحدة.

يبدو أن الطريقة الأسهل هي أخذ العرض والاستعلام عنه المكتوب بالفعل في الدرس 11، ودمجهما في إجراء مخزن وجعل معرف البائع (id_vendor) معلمة إدخال، مثل هذا:

إنشاء إجراء sum_vendor(i INT) البدء في إنشاء عرض report_vendor AS SELECT Magazine_incoming.id_product، Magazine_incoming.quantity،الأسعار.price، Magazine_incoming.quantity*prices.price كمجموع من مجلة_incoming، الأسعار من حيث المجلة_incoming.id_product=الأسعار.id_product وid_incoming= ( حدد id_incoming FROM الوارد حيث id_vendor=i); حدد SUM(summa) من report_vendor؛ نهاية //

لكن الإجراء لن يعمل بهذه الطريقة. بيت القصيد هو أن لا يمكن لطرق العرض استخدام المعلمات. ولذلك، سيتعين علينا تغيير تسلسل الطلبات قليلاً. أولاً، سنقوم بإنشاء طريقة عرض تعرض معرف البائع (id_vendor)، ومعرف المنتج (id_product)، والكمية (quantity)، والسعر (price)، والمجموع (summa) من الجداول الثلاثة الإمدادات (الواردة)، والمجلة (المجلة_الواردة) , الأسعار ( الأسعار ):

إنشاء عرض report_vendor AS تحديد incoming.id_vendor، Magazine_incoming.id_product، Magazine_incoming.quantity،الأسعار.price، Magazine_incoming.quantity*prices.price كملخص من الوارد، مجلة_incoming، الأسعار حيث المجلة_incoming.id_product=الأسعار.id_product AND Magazine_incoming.id_incoming= incoming .id_incoming;

وبعد ذلك سنقوم بإنشاء استعلام يلخص كميات العرض للمورد الذي نهتم به، على سبيل المثال، باستخدام id_vendor=2:

يمكننا الآن دمج هذين الاستعلامين في إجراء مخزن، حيث ستكون معلمة الإدخال هي معرف البائع (id_vendor)، والذي سيتم استبداله في الاستعلام الثاني، ولكن ليس في العرض:

إنشاء إجراء sum_vendor(i INT) البدء في إنشاء عرض report_vendor AS SELECT incoming.id_vendor، Magazine_incoming.id_product، Magazine_incoming.quantity،الأسعار، Magazine_incoming.quantity*prices.price كملخص من الوارد، مجلة_incoming، الأسعار حيث المجلة_incoming.id_product= الأسعار .id_product AND Magazine_incoming.id_incoming= incoming.id_incoming; حدد SUM(summa) من report_vendor حيث id_vendor=i; نهاية //


دعونا نتحقق من تشغيل الإجراء باستخدام معلمات الإدخال المختلفة:


كما ترون، يتم تشغيل الإجراء مرة واحدة ثم يُظهر خطأً يخبرنا أن طريقة العرض report_vendor موجودة بالفعل في قاعدة البيانات. وذلك لأنه عند استدعاء الإجراء لأول مرة، فإنه يقوم بإنشاء طريقة عرض. عند الوصول إليها مرة ثانية، تحاول إنشاء العرض مرة أخرى، ولكنه موجود بالفعل، وهذا هو سبب ظهور الخطأ. لتجنب هذا هناك خياران.

الأول هو إخراج التمثيل من الإجراء. أي أننا سنقوم بإنشاء العرض مرة واحدة، وسيقوم الإجراء بالوصول إليه فقط، ولكن لن نقوم بإنشائه. لا تنس حذف الإجراء الذي تم إنشاؤه بالفعل وعرضه أولاً:

إسقاط الإجراء sum_vendor// إسقاط العرض report_vendor// إنشاء عرض report_vendor AS SELECT incoming.id_vendor، مجلة_incoming.id_product، مجلة_incoming.quantity، الأسعار، Magazine_incoming.quantity*prices.price كملخص من الوارد، مجلة_incoming، الأسعار حيث Magazine_incoming.id_product =الأسعار.id_product AND Magazine_incoming.id_incoming= incoming.id_incoming // إنشاء إجراء sum_vendor(i INT) begin SELECT SUM(summa) FROM report_vendor WHERE id_vendor=i; نهاية //


التحقق من العمل:

اتصل بـ sum_vendor(1)// اتصل بـ sum_vendor(2)// اتصل بـ sum_vendor(3)//


الخيار الثاني هو إضافة أمر مباشرة في الإجراء الذي سيحذف العرض إذا كان موجودًا:

إنشاء إجراء sum_vendor(i INT) البدء في إسقاط العرض إذا كان موجودًا report_vendor; إنشاء عرض report_vendor AS تحديد incoming.id_vendor، Magazine_incoming.id_product، Magazine_incoming.quantity،الأسعار.price، Magazine_incoming.quantity*prices.price كملخص من الوارد، مجلة_incoming، الأسعار حيث المجلة_incoming.id_product=الأسعار.id_product AND Magazine_incoming.id_incoming= incoming .id_incoming; حدد SUM(summa) من report_vendor حيث id_vendor=i; نهاية //

قبل استخدام هذا الخيار، تأكد من إزالة الإجراء sum_vendor ثم اختبار العمل:

كما ترون، من الأسهل حقًا إضفاء الطابع الرسمي على الاستعلامات المعقدة أو تسلسلها مرة واحدة في إجراء مخزن، ثم الوصول إليها ببساطة، مع تحديد المعلمات الضرورية. يؤدي هذا إلى تقليل التعليمات البرمجية بشكل كبير ويجعل العمل مع الاستعلامات أكثر منطقية.

قم بتضمين سطر في إجراءاتك - قم بتعيين NOCOUNT ON:

مع كل تعبير DML، يقوم خادم SQL بإرجاع رسالة تحتوي على عدد السجلات التي تمت معالجتها بعناية. قد تكون هذه المعلومات مفيدة لنا أثناء تصحيح التعليمات البرمجية، ولكن بعد ذلك ستكون عديمة الفائدة تمامًا. من خلال كتابة SET NOCOUNT ON، نقوم بتعطيل هذه الوظيفة. بالنسبة للإجراءات المخزنة التي تحتوي على تعبيرات و/أو حلقات متعددة، يمكن أن يؤدي هذا الإجراء إلى زيادة كبيرة في الأداء، لأنه سيتم تقليل كمية حركة المرور بشكل كبير.

المعاملات SQL

استخدم اسم المخطط مع اسم الكائن:

حسنًا، أعتقد أن الأمر واضح. تخبر هذه العملية الخادم بمكان البحث عن الكائنات وبدلاً من البحث العشوائي في صناديقه، سيعرف على الفور المكان الذي يجب أن يذهب إليه وما الذي يجب أن يأخذه. مع وجود عدد كبير من قواعد البيانات والجداول والإجراءات المخزنة، يمكن أن يوفر وقتنا وأعصابنا بشكل كبير.

المعاملات SQL

SELECT * FROM dbo.MyTable - يعد القيام بذلك بهذه الطريقة أمرًا جيدًا - بدلاً من SELECT * FROM MyTable - والقيام بذلك بهذه الطريقة أمر سيء - استدعاء إجراء EXEC dbo.MyProc - جيد مرة أخرى - بدلاً من EXEC MyProc --سيء!

لا تستخدم البادئة "sp_" في اسم إجراءاتك المخزنة:

إذا كان اسم الإجراء الخاص بنا يبدأ بـ "sp_"، فسوف يبحث SQL Server في قاعدة البيانات الرئيسية الخاصة به أولاً. الحقيقة هي أن هذه البادئة تُستخدم للإجراءات الشخصية المخزنة داخليًا للخادم. ولذلك، فإن استخدامه قد يؤدي إلى تكاليف إضافية وحتى نتائج غير صحيحة إذا تم العثور على إجراء يحمل نفس الاسم الخاص بك في قاعدة البيانات الخاصة به.

استخدم IF EXISTS (SELECT 1) بدلاً من IF EXISTS (SELECT *):

للتحقق من وجود سجل في جدول آخر، نستخدم عبارة IF EXISTS. يعود هذا التعبير صحيحًا إذا تم إرجاع قيمة واحدة على الأقل من التعبير الداخلي، فلا يهم "1" أو جميع الأعمدة أو الجدول. لا يتم استخدام البيانات التي تم إرجاعها بأي شكل من الأشكال. وبالتالي، لضغط حركة المرور أثناء نقل البيانات، فمن المنطقي أكثر استخدام "1"، كما هو موضح أدناه.

آخر تحديث: 14/08/2017

في كثير من الأحيان، تمثل عملية البيانات مجموعة من التعليمات التي يجب تنفيذها في تسلسل معين. على سبيل المثال، عند إضافة شراء منتج، تحتاج إلى إدخال البيانات في جدول الطلبات. ومع ذلك، قبل القيام بذلك، تحتاج إلى التحقق مما إذا كان المنتج الذي تشتريه متوفرًا في المخزون. قد تحتاج إلى التحقق من عدد من الشروط الإضافية. وهذا هو، في الواقع، عملية شراء المنتج تغطي العديد من الإجراءات التي يجب تنفيذها في تسلسل معين. وفي هذه الحالة، سيكون من الأفضل تجميع كل هذه الإجراءات في كائن واحد - الإجراء المخزن(الإجراء المخزن).

وهذا يعني، في جوهره، أن الإجراءات المخزنة هي مجموعة من التعليمات التي يتم تنفيذها كوحدة واحدة. وبالتالي، فإن الإجراءات المخزنة تجعل من الممكن تبسيط العمليات المعقدة ووضعها في كائن واحد. ستتغير عملية شراء المنتج وفقًا لذلك، وسيكون كافيًا تغيير رمز الإجراء. وهذا يعني أن الإجراء يبسط أيضًا إدارة التعليمات البرمجية.

تسمح لك الإجراءات المخزنة أيضًا بتقييد الوصول إلى البيانات الموجودة في الجداول وبالتالي تقليل احتمالية الإجراءات غير المرغوب فيها المقصودة أو غير المقصودة فيما يتعلق بهذه البيانات.

وجانب آخر مهم هو الأداء. عادةً ما يتم تنفيذ الإجراءات المخزنة بشكل أسرع من عبارات SQL العادية. وذلك لأن رمز الإجراء يتم تجميعه مرة واحدة عند تشغيله لأول مرة، ثم يتم حفظه في نموذج مترجم.

لإنشاء إجراء مخزن، استخدم الأمر CREATE PROCEDURE أو CREATE PROC.

وبالتالي، فإن الإجراء المخزن له ثلاث ميزات رئيسية: تبسيط التعليمات البرمجية، والأمن، والأداء.

على سبيل المثال، لنفترض أن هناك جدولًا في قاعدة البيانات يقوم بتخزين بيانات حول المنتجات:

إنشاء منتجات الجدول (معرف INT IDENTITY KEY، اسم المنتج NVARCHAR(30) غير فارغ، الشركة المصنعة NVARCHAR(20) ليست فارغة، ProductCount INT DEFAULT 0، السعر MONEY NOT NULL)؛

لنقم بإنشاء إجراء مخزن لاسترداد البيانات من هذا الجدول:

استخدام المنتجاتdb؛ انتقل إلى إنشاء إجراء ملخص المنتج كما حدد اسم المنتج كمنتج، الشركة المصنعة، السعر من المنتجات

نظرًا لأنه يجب استدعاء الأمر CREATE PROCEDURE في حزمة منفصلة، ​​فإن الأمر USE الذي يقوم بتعيين قاعدة البيانات الحالية يتبعه أمر GO لتحديد حزمة جديدة.

يجب أن يتبع اسم الإجراء الكلمة الأساسية AS.

لفصل نص الإجراء عن بقية البرنامج النصي، غالبًا ما يتم وضع رمز الإجراء في كتلة BEGIN...END:

استخدام المنتجاتdb؛ انتقل إلى إنشاء إجراء ملخص المنتج كما تبدأ، حدد اسم المنتج كمنتج، الشركة المصنعة، السعر من نهاية المنتجات؛

بعد إضافة الإجراء، يمكننا رؤيته في عقدة قاعدة البيانات في SQL Server Management Studio في العقدة الفرعية قابلية البرمجة -> الإجراءات المخزنة:

وسنكون قادرين على التحكم في الإجراء من خلال واجهة مرئية أيضًا.

تنفيذ الإجراء

لتنفيذ إجراء مخزن، اتصل بالأمر EXEC أو EXECUTE:

ملخص منتج EXEC

إزالة الإجراء

لإزالة إجراء ما، استخدم أمر DROP PROCEDURE:

ملخص المنتج لإجراءات الإسقاط

الإجراء المخزنهو نوع خاص من حزمة بيانات Transact-SQL التي تم إنشاؤها باستخدام لغة SQL والامتدادات الإجرائية. والفرق الرئيسي بين الحزمة والإجراء المخزن هو أن الأخير يتم تخزينه ككائن قاعدة بيانات. بمعنى آخر، يتم تخزين الإجراءات المخزنة على جانب الخادم لتحسين الأداء واتساق المهام القابلة للتكرار.

يدعم محرك قاعدة البيانات الإجراءات المخزنة وإجراءات النظام. يتم إنشاء الإجراءات المخزنة بنفس الطريقة التي يتم بها إنشاء كافة كائنات قاعدة البيانات الأخرى، أي. باستخدام لغة DDL. إجراءات النظاميتم توفيرها بواسطة محرك قاعدة البيانات ويمكن استخدامها للوصول إلى المعلومات وتعديلها في كتالوج النظام.

عندما تقوم بإنشاء إجراء مخزن، يمكنك تحديد قائمة اختيارية من المعلمات. بهذه الطريقة، سيقبل الإجراء الوسائط المناسبة في كل مرة يتم استدعاؤه. يمكن أن تقوم الإجراءات المخزنة بإرجاع قيمة تحتوي على معلومات محددة من قبل المستخدم أو، في حالة حدوث خطأ، رسالة خطأ مناسبة.

يتم ترجمة الإجراء المخزن مسبقًا قبل تخزينه ككائن في قاعدة البيانات. يتم تخزين نموذج الإجراء المترجم مسبقًا في قاعدة البيانات واستخدامه في كل مرة يتم استدعاؤه. توفر خاصية الإجراءات المخزنة هذه فائدة مهمة تتمثل في إزالة مجموعات الإجراءات المتكررة (في جميع الحالات تقريبًا) وتحقيق تحسينات الأداء المقابلة. خاصية الإجراءات المخزنة هذه لها أيضًا تأثير إيجابي على كمية البيانات المتبادلة بين نظام قاعدة البيانات والتطبيقات. على وجه الخصوص، قد يتطلب استدعاء إجراء مخزن يبلغ حجمه عدة آلاف من البايتات أقل من 50 بايت. عندما يقوم العديد من المستخدمين بتنفيذ مهام متكررة باستخدام الإجراءات المخزنة، يمكن أن يكون التأثير التراكمي لهذه المدخرات كبيرًا جدًا.

يمكن أيضًا استخدام الإجراءات المخزنة للأغراض التالية:

    لإنشاء سجل الإجراءات مع جداول قاعدة البيانات.

يوفر استخدام الإجراءات المخزنة مستوى من التحكم الأمني ​​يتجاوز الأمان المقدم باستخدام عبارات GRANT وREVOKE، التي تمنح امتيازات وصول مختلفة للمستخدمين. وهذا ممكن لأن ترخيص تنفيذ إجراء مخزن مستقل عن ترخيص تعديل الكائنات الموجودة في الإجراء المخزن، كما هو موضح في القسم التالي.

توفر الإجراءات المخزنة التي تنشئ سجلات لعمليات كتابة و/أو قراءة الجدول خيارًا إضافيًا لأمان قاعدة البيانات. باستخدام مثل هذه الإجراءات، يمكن لمسؤول قاعدة البيانات مراقبة التعديلات التي يتم إجراؤها على قاعدة البيانات بواسطة المستخدمين أو برامج التطبيقات.

إنشاء وتنفيذ الإجراءات المخزنة

يتم إنشاء الإجراءات المخزنة باستخدام عبارة إنشاء الإجراء، والذي يحتوي على بناء الجملة التالي:

إنشاء PROC proc_name [((@param1) type1 [VARYING] [= default1] )] (، ...) كدفعة | الاسم الخارجي، اسم الأسلوب، اصطلاحات بناء الجملة

تحدد المعلمة schema_name اسم المخطط الذي تم تعيينه بواسطة مالك الإجراء المخزن الذي تم إنشاؤه. تحدد المعلمة proc_name اسم الإجراء المخزن. المعلمة @param1 هي معلمة إجراء (وسيطة رسمية) يتم تحديد نوع بياناتها بواسطة المعلمة type1. تعد معلمات الإجراء محلية داخل الإجراء، تمامًا كما تكون المتغيرات المحلية محلية داخل الحزمة. معلمات الإجراء هي القيم التي يمررها المتصل إلى الإجراء لاستخدامها فيه. تحدد المعلمة default1 القيمة الافتراضية لمعلمة الإجراء المقابلة. (يمكن أن تكون القيمة الافتراضية فارغة أيضًا.)

خيار الإخراجيشير إلى أن معلمة الإجراء هي معلمة إرجاع ويمكن استخدامها لإرجاع قيمة من إجراء مخزن إلى إجراء الاستدعاء أو النظام.

كما ذكرنا سابقًا، يتم تخزين نموذج الإجراء المترجم مسبقًا في قاعدة البيانات واستخدامه في كل مرة يتم استدعاؤه. إذا كان هناك حاجة إلى تجميع الإجراء المخزن لسبب ما في كل مرة يتم استدعاؤه، عند الإعلان عن الإجراء، استخدمه مع خيار إعادة الترجمة. يؤدي استخدام خيار "مع إعادة الترجمة" إلى إبطال إحدى أهم فوائد الإجراءات المخزنة: تحسين الأداء نتيجة لتجميع واحد. ولذلك، يجب استخدام الخيار مع إعادة الترجمة فقط عندما يتم تعديل كائنات قاعدة البيانات المستخدمة بواسطة الإجراء المخزن بشكل متكرر.

تنفيذ AS جملةيحدد سياق الأمان الذي يجب تنفيذ الإجراء المخزن فيه بعد استدعائه. من خلال تعيين هذا السياق، يمكن لمحرك قاعدة البيانات التحكم في تحديد حسابات المستخدمين للتحقق من أذونات الوصول إلى الكائنات المشار إليها بواسطة الإجراء المخزن.

افتراضيًا، يمكن فقط لأعضاء دور الخادم الثابت لمسؤول النظام وأدوار قاعدة البيانات الثابتة db_owner أو db_ddladmin استخدام عبارة CREATE PROCEDURE. لكن يمكن لأعضاء هذه الأدوار تعيين هذا الحق لمستخدمين آخرين باستخدام العبارة إجراء إنشاء المنحة.

يوضح المثال أدناه كيفية إنشاء إجراء مخزن بسيط للعمل مع جدول المشروع:

استخدم SampleDb; انتقل إلى إجراء الإنشاء زيادة الميزانية (@percent INT=5) كتحديث لمجموعة المشروع الميزانية = الميزانية + الميزانية * @percent/100;

كما ذكرنا سابقًا، لفصل الحزمتين، استخدم تعليمات الذهاب. لا يمكن دمج عبارة CREATE PROCEDURE مع عبارات Transact-SQL الأخرى في نفس الدفعة. يؤدي الإجراء المخزن "زيادة الميزانية" إلى زيادة الميزانيات لكافة المشاريع بنسبة مئوية معينة، يتم تحديدها بواسطة المعلمة @percent. يحدد الإجراء أيضًا قيمة النسبة المئوية الافتراضية (5) التي يتم استخدامها في حالة عدم وجود هذه الوسيطة عند تشغيل الإجراء.

يمكن للإجراءات المخزنة الوصول إلى الجداول غير الموجودة. تسمح لك هذه الخاصية بتصحيح كود الإجراء دون إنشاء الجداول المناسبة أولاً أو حتى الاتصال بالخادم الوجهة.

على عكس الإجراءات المخزنة الأساسية، التي يتم تخزينها دائمًا في قاعدة البيانات الحالية، من الممكن إنشاء إجراءات مخزنة مؤقتة يتم تخزينها دائمًا في قاعدة بيانات النظام المؤقتة tempdb. قد يكون أحد أسباب إنشاء إجراءات مخزنة مؤقتة هو تجنب تنفيذ مجموعة معينة من البيانات بشكل متكرر عند الاتصال بقاعدة بيانات. يمكنك إنشاء إجراءات مؤقتة محلية أو عالمية. للقيام بذلك، يتم تحديد اسم الإجراء المحلي بحرف # واحد (#proc_name)، ويتم تحديد اسم الإجراء العام بحرف مزدوج (##proc_name).

لا يمكن تنفيذ الإجراء المحلي المخزن المؤقت إلا بواسطة المستخدم الذي قام بإنشائه، وفقط أثناء الاتصال بقاعدة البيانات التي تم إنشاؤه فيها. يمكن تنفيذ الإجراء المؤقت العام من قبل جميع المستخدمين، ولكن فقط حتى ينتهي الاتصال الأخير الذي تم تنفيذه عليه (عادةً اتصال منشئ الإجراء).

تتكون دورة حياة الإجراء المخزن من مرحلتين: إنشائه وتنفيذه. يتم إنشاء كل إجراء مرة واحدة ويتم تنفيذه عدة مرات. يتم تنفيذ الإجراء المخزن باستخدام تنفيذ التعليماتمستخدم هو مالك الإجراء أو لديه امتياز التنفيذ للوصول إلى هذا الإجراء. تحتوي عبارة EXECUTE على بناء الجملة التالي:

[] [@return_status =] (proc_name | @proc_name_var) ([[@parameter1 =] value | [@parameter1=] @variable ] | DEFAULT).. اصطلاحات بناء الجملة

باستثناء المعلمة return_status، فإن كافة معلمات عبارة EXECUTE لها نفس المعنى المنطقي مثل نفس معلمات عبارة CREATE PROCEDURE. تحدد المعلمة return_status متغيرًا صحيحًا يخزن حالة الإرجاع للإجراء. يمكن تعيين قيمة لمعلمة باستخدام ثابت (قيمة) أو متغير محلي (@variable). ترتيب قيم المعلمات المسماة ليس مهمًا، ولكن يجب توفير قيم المعلمات غير المسماة بالترتيب الذي تم تعريفها به في عبارة CREATE PROCEDURE.

الجملة الافتراضيةيوفر القيمة الافتراضية لمعلمة الإجراء التي تم تحديدها في تعريف الإجراء. عندما يتوقع الإجراء قيمة لمعلمة لم يتم تحديد قيمة افتراضية لها وكانت المعلمة مفقودة أو تم تحديد الكلمة الأساسية الافتراضية، يحدث خطأ.

عندما تكون عبارة التنفيذ هي العبارة الأولى للمجموعة، يمكن حذف الكلمة الأساسية EXECUTE. ومع ذلك، فمن الأفضل تضمين هذه الكلمة في كل حزمة. يظهر استخدام عبارة EXECUTE في المثال أدناه:

استخدم SampleDb; تنفيذ زيادة الميزانية 10؛

تقوم عبارة EXECUTE في هذا المثال بتنفيذ الإجراء المخزن BoostBudget، مما يؤدي إلى زيادة ميزانية كافة المشاريع بنسبة 10%.

يوضح المثال أدناه كيفية إنشاء إجراء مخزن لمعالجة البيانات في جدولي الموظف وWorks_on:

يوضح الإجراء المثال ModifyEmpId استخدام الإجراءات المخزنة كجزء من عملية الحفاظ على التكامل المرجعي (في هذه الحالة بين جدولي الموظف وWorks_on). يمكن استخدام إجراء مخزن مماثل داخل تعريف المشغل، والذي يوفر في الواقع التكامل المرجعي.

يوضح المثال التالي استخدام عبارة OUTPUT في إجراء مخزن:

يمكن تنفيذ هذا الإجراء المخزن باستخدام الإرشادات التالية:

أعلن @quantityDeleteEmployee INT؛ تنفيذ حذف الموظف @empId=18316, @OUTPUT; PRINT N"الموظفون المحذوفون: " + converter(nvarchar(30), @quantityDeleteEmployee);

يقوم هذا الإجراء بحساب عدد المشاريع التي يعمل عليها الموظف صاحب رقم الموظف @empId ويقوم بتعيين القيمة الناتجة إلى المعلمة ©counter. بعد حذف كافة الصفوف الخاصة برقم موظف معين من جدولي الموظف وWorks_on، يتم تعيين القيمة المحسوبة إلى المتغير @quantityDeleteEmployee.

يتم إرجاع قيمة المعلمة إلى إجراء الاستدعاء فقط إذا تم تحديد خيار OUTPUT. في المثال أعلاه، يقوم الإجراء RemoveEmployee بتمرير المعلمة @counter إلى إجراء الاستدعاء، ومن ثم يقوم الإجراء المخزن بإرجاع قيمة إلى النظام. لذلك، يجب تحديد المعلمة @counter في خيار OUTPUT عند الإعلان عن إجراء ما وفي عبارة EXECUTE عند استدعائه.

مع جملة النتائج لبيان التنفيذ

في SQL Server 2012، بالنسبة لبيان التنفيذ، تقوم بإدخاله مع جملة النتائج، والتي من خلالها، عند استيفاء شروط معينة، يمكنك تغيير شكل مجموعة النتائج الخاصة بالإجراء المخزن.

سيساعد المثالان التاليان في شرح هذه الجملة. المثال الأول هو مثال تمهيدي يوضح الشكل الذي قد تبدو عليه النتيجة عند حذف جملة "مع نتائج مجموعات":

يعد إجراء EmploysInDept إجراءً بسيطًا يعرض أرقام الموظفين والأسماء الأخيرة لجميع الموظفين العاملين في قسم معين. رقم القسم هو معلمة إجراء ويجب تحديده عند الاتصال به. يؤدي تنفيذ هذا الإجراء إلى إنتاج جدول يحتوي على عمودين تتطابق عناوينهما مع أسماء الأعمدة المقابلة في جدول قاعدة البيانات، أي. معرف واسم العائلة. لتغيير رؤوس أعمدة النتائج (بالإضافة إلى نوع البيانات الخاصة بها)، يستخدم SQL Server 2012 عبارة "مع مجموعات النتائج" الجديدة. وتطبيق هذه الجملة يظهر في المثال التالي:

استخدم SampleDb; EXEC EmployersInDept "d1" مع مجموعات النتائج ((INT NOT NULL, [LastName] CHAR(20) NOT NULL));

ستكون نتيجة تنفيذ الإجراء المخزن الذي يتم استدعاؤه بهذه الطريقة كما يلي:

كما ترون، فإن تشغيل إجراء مخزن باستخدام جملة With RESULT SETS في عبارة EXECUTE يسمح لك بتغيير أسماء وأنواع بيانات الأعمدة في مجموعة النتائج التي ينتجها الإجراء. وبالتالي، توفر هذه الوظيفة الجديدة مرونة أكبر في تنفيذ الإجراءات المخزنة ووضع نتائجها في جدول جديد.

تغيير هيكل الإجراءات المخزنة

يدعم محرك قاعدة البيانات أيضًا التعليمات تغيير الإجراءلتعديل هيكل الإجراءات المخزنة. يتم عادةً استخدام عبارة ALTER PROCEDURE لتغيير عبارات Transact-SQL ضمن الإجراء. جميع معلمات عبارة ALTER PROCEDURE لها نفس معنى نفس معلمات عبارة CREATE PROCEDURE. الغرض الرئيسي من استخدام هذا البيان هو تجنب تجاوز حقوق الإجراءات المخزنة الموجودة.

يدعم محرك قاعدة البيانات نوع بيانات المؤشر. يتم استخدام نوع البيانات هذا للإعلان عن المؤشرات في الإجراءات المخزنة. المؤشرعبارة عن بناء برمجي يستخدم لتخزين نتائج الاستعلام (عادةً مجموعة من الصفوف) والسماح للمستخدمين بعرض هذه النتيجة صفًا تلو الآخر.

لحذف واحد أو مجموعة من الإجراءات المخزنة، استخدم تعليمات إجراءات الإسقاط. يمكن فقط للمالك أو الأعضاء في الأدوار الثابتة لـ db_owner وsysadmin حذف الإجراء المخزن.

الإجراءات المخزنة ووقت تشغيل اللغة المشتركة

يدعم SQL Server وقت تشغيل اللغة العامة (CLR)، الذي يسمح لك بتطوير كائنات قاعدة البيانات المتنوعة (الإجراءات المخزنة، والوظائف المعرفة من قبل المستخدم، والمشغلات، والمجموعات المعرفة من قبل المستخدم، وأنواع البيانات المخصصة) باستخدام C# وVisual Basic. يسمح لك CLR أيضًا بتنفيذ هذه الكائنات باستخدام نظام وقت التشغيل المشترك.

يتم تمكين وتعطيل وقت تشغيل اللغة العامة باستخدام هذا الخيار clr_enabledإجراء النظام sp_configure، والذي يتم إطلاقه للتنفيذ عن طريق التعليمات إعادة التكوين. يوضح المثال التالي كيف يمكنك استخدام إجراء النظام sp_configure لتمكين CLR:

استخدم SampleDb; EXEC sp_configure "clr_enabled"، 1 إعادة التكوين

لإنشاء إجراء وتجميعه وحفظه باستخدام CLR، يجب عليك إكمال التسلسل التالي من الخطوات بالترتيب الموضح:

    قم بإنشاء إجراء مخزن في C# أو Visual Basic، ثم قم بتجميعه باستخدام المترجم المناسب.

    باستخدام التعليمات إنشاء الجمعية، قم بإنشاء الملف القابل للتنفيذ المقابل.

    قم بتنفيذ الإجراء باستخدام عبارة EXECUTE.

يوضح الشكل أدناه رسمًا بيانيًا للخطوات الموضحة مسبقًا. وفيما يلي وصف أكثر تفصيلا لهذه العملية.

أولاً، قم بإنشاء البرنامج المطلوب في بيئة تطوير مثل Visual Studio. قم بتجميع البرنامج النهائي إلى رمز كائن باستخدام برنامج التحويل البرمجي C# أو Visual Basic. يتم تخزين هذا الرمز في ملف مكتبة الارتباط الديناميكي (.dll)، والذي يعمل كمصدر لعبارة CREATE ASSEMBLY، التي تقوم بإنشاء التعليمات البرمجية المتوسطة القابلة للتنفيذ. بعد ذلك، قم بإصدار عبارة CREATE PROCEDURE لحفظ التعليمات البرمجية المنفذة ككائن قاعدة بيانات. وأخيراً، قم بتشغيل الإجراء باستخدام عبارة EXECUTE المألوفة.

يوضح المثال أدناه التعليمات البرمجية المصدر لإجراء مخزن في C#:

باستخدام System.Data.SqlClient؛ باستخدام Microsoft.SqlServer.Server؛ فئة عامة جزئية StoredProcedures (عام ثابت عدد CountEmployees () (صفوف int؛ اتصال SqlConnection = جديد SqlConnection("Context Connection=true"); Connection.Open(); SqlCommand cmd = Connection.CreateCommand(); cmd.CommandText = "select عد (*) كـ "عدد الموظفين" " + "من الموظف"؛ الصفوف = (int)cmd.ExecuteScalar(); Connection.Close(); صفوف الإرجاع؛ ) )

ينفذ هذا الإجراء استعلامًا لحساب عدد الصفوف في جدول الموظف. باستخدام التوجيهات في بداية البرنامج، يمكنك تحديد مساحات الأسماء المطلوبة لتنفيذ البرنامج. يتيح لك استخدام هذه التوجيهات تحديد أسماء الفئات في التعليمات البرمجية المصدر دون تحديد مساحات الأسماء المقابلة بشكل صريح. بعد ذلك، يتم تعريف فئة StoredProcedures، والتي سمة SqlProcedure، والذي يُعلم المترجم أن هذه الفئة عبارة عن إجراء مخزن. يتم تعريف أسلوب CountEmployees () داخل رمز الفصل. يتم إنشاء اتصال بنظام قاعدة البيانات من خلال مثيل للفئة اتصال SQL. لفتح اتصال، يتم استخدام أسلوب Open() لهذا المثيل. أ طريقة إنشاء الأمر ().يسمح لك بالوصول إلى مثيل للفئة SQLCommnd، والذي يتم تمرير أمر SQL المطلوب إليه.

في مقتطف الكود التالي:

Cmd.CommandText = "اختر العد (*) كـ "عدد الموظفين"" + "من الموظف"؛

يستخدم عبارة SELECT لحساب عدد الصفوف في جدول الموظف وعرض النتيجة. يتم تحديد نص الأمر عن طريق تعيين خاصية CommandText للمتغير cmd إلى المثيل الذي يتم إرجاعه بواسطة الأسلوب CreateCommand(). التالي يطلق عليه طريقة ExecuteScalar ().مثيل SqlCommand. تقوم هذه الطريقة بإرجاع قيمة عددية يتم تحويلها إلى نوع بيانات عدد صحيح وتعيينها لمتغير الصفوف.

يمكنك الآن ترجمة هذا الرمز باستخدام Visual Studio. لقد أضفت هذه الفئة إلى مشروع يسمى CLRStoredProcedures، لذلك سيقوم Visual Studio بتجميع تجميع يحمل نفس الاسم بملحق *.dll. يوضح المثال أدناه الخطوة التالية في إنشاء إجراء مخزن: إنشاء التعليمات البرمجية القابلة للتنفيذ. قبل تشغيل التعليمات البرمجية في هذا المثال، تحتاج إلى معرفة موقع ملف dll المترجم (الموجود عادةً في مجلد Debug الخاص بالمشروع).

استخدم SampleDb; انتقل إلى إنشاء تجميع CLRStoredProcedures من "D:\Projects\CLRStoredProcedures\bin\Debug\CLRStoredProcedures.dll" مع PERMISSION_SET = SAFE

تأخذ عبارة CREATE ASSEMBLY التعليمات البرمجية المُدارة كمدخلات وتقوم بإنشاء كائن مناظر يمكنك من خلاله إنشاء إجراءات CLR المخزنة والوظائف المحددة من قبل المستخدم والمشغلات. تحتوي هذه التعليمات على بناء الجملة التالي:

إنشاء التجميع اسم_الجمع [اسم مالك التفويض] من (ملف_dll) اصطلاحات بناء الجملة

تحدد المعلمة Assembly_name اسم التجميع. تحدد جملة التفويض الاختيارية اسم الدور كمالك لهذا التجميع. تحدد جملة FROM المسار الذي يوجد به التجميع المراد تحميله.

مع جملة PERMISSION_SETيعد بندًا مهمًا جدًا في عبارة CREATE ASSEMBLY ويجب تحديده دائمًا. فهو يحدد مجموعة الأذونات الممنوحة لرمز التجميع. مجموعة الأذونات الآمنة هي الأكثر تقييدًا. لا يمكن لرمز التجميع الذي يتمتع بهذه الحقوق الوصول إلى موارد النظام الخارجية مثل الملفات. تسمح مجموعة الحقوق EXTERNAL_ACCESS لرمز التجميع بالوصول إلى بعض موارد النظام الخارجية، بينما تسمح مجموعة الحقوق UNSAFE بالوصول غير المقيد إلى الموارد داخل نظام قاعدة البيانات وخارجه.

لحفظ معلومات رمز التجميع، يجب أن يكون المستخدم قادرًا على إصدار عبارة CREATE ASSEMBLY. مالك التجميع هو المستخدم (أو الدور) الذي ينفذ التعليمات. يمكنك جعل مستخدم آخر مالك التجميع باستخدام جملة التفويض في عبارة CREATE SCHEMA.

يدعم محرك قاعدة البيانات أيضًا عبارات ALTER ASSEMBLY وDROP ASSEMBLY. تغيير بيان الجمعيةيستخدم لتحديث التجميع إلى الإصدار الأحدث. تقوم هذه التعليمات أيضًا بإضافة أو إزالة الملفات المرتبطة بالتجميع المقابل. إسقاط تعليمات التجميعإزالة التجميع المحدد وكافة الملفات المرتبطة به من قاعدة البيانات الحالية.

يوضح المثال أدناه كيفية إنشاء إجراء مخزن بناءً على التعليمات البرمجية المُدارة التي قمت بتنفيذها مسبقًا:

استخدم SampleDb; انتقل إلى إنشاء إجراء CountEmployees كاسم خارجي CLRStoredProcedures.StoredProcedures.CountEmployees

تختلف تعليمات CREATE PROCEDURE في المثال عن نفس التعليمات في الأمثلة السابقة من حيث أنها تحتوي على معلمة الاسم الخارجي. يحدد هذا الخيار أن التعليمات البرمجية يتم إنشاؤها بواسطة وقت تشغيل اللغة العامة. يتكون الاسم في هذه الجملة من ثلاثة أجزاء:

Assembly_name.class_name.method_name

    اسم التجميع - يشير إلى اسم التجميع؛

    class_name - يشير إلى اسم الفئة العامة؛

    اسم_الطريقة - جزء اختياري، يحدد اسم الطريقة التي تم تعريفها داخل الفصل.

يظهر تنفيذ الإجراء CountEmployees في المثال أدناه:

استخدم SampleDb; إعلان @count INT تنفيذ @count = CountEmployees طباعة @count -- إرجاع 7

تقوم عبارة PRINT بإرجاع العدد الحالي من الصفوف في جدول الموظف.

بالنسبة لبرمجة الإجراءات المخزنة الموسعة، توفر Microsoft واجهة برمجة تطبيقات ODS (خدمة البيانات المفتوحة)، وهي مجموعة من وحدات الماكرو والوظائف المستخدمة لإنشاء تطبيقات الخادم التي تسمح لك بتوسيع وظائف MS SQL Server 2000.

الإجراءات المخزنة الموسعة هي وظائف عادية مكتوبة بلغة C/C++ باستخدام ODS API وWIN32 API، وهي مصممة كمكتبة ارتباط ديناميكية (dll) ومصممة، كما قلت سابقًا، لتوسيع وظائف خادم SQL. توفر واجهة برمجة تطبيقات ODS للمطور مجموعة غنية من الوظائف التي تسمح لك بنقل البيانات إلى العميل المستلمة من أي مصدر بيانات خارجي في شكل مجموعات سجلات عادية. كما يمكن للإجراء المخزن الموسع إرجاع القيم من خلال المعلمة التي تم تمريرها إليه (معلمة OUTPUT).

كيف تعمل الإجراءات المخزنة الموسعة.

  • عندما يستدعي تطبيق العميل إجراءً مخزنًا موسعًا، يتم إرسال الطلب بتنسيق TDS من خلال Net-Libraries وOpen Data Service إلى قلب MS SQL SERVER.
  • يعثر SQL Sever على مكتبة dll المرتبطة باسم الإجراء المخزن الموسع ويقوم بتحميلها في سياقها، إذا لم يتم تحميلها هناك من قبل، ويستدعي الإجراء المخزن الموسع الذي تم تنفيذه كوظيفة داخل ملف dll.
  • ينفذ الإجراء المخزن الموسع الإجراءات اللازمة على الخادم وينقل مجموعة من النتائج إلى تطبيق العميل باستخدام الخدمة التي توفرها واجهة برمجة تطبيقات ODS.

ميزات الإجراءات المخزنة الموسعة.

  • الإجراءات المخزنة الموسعة هي وظائف يتم تنفيذها في مساحة عنوان MS SQL Server وفي سياق الأمان الخاص بالحساب الذي تعمل بموجبه خدمة MS SQL Server؛
  • بمجرد تحميل ملف dll الخاص بالإجراء المخزن الموسع في الذاكرة، فإنه يظل هناك حتى يتم إيقاف SQL Server، أو حتى يجبره المسؤول على إلغاء تحميله باستخدام الأمر:
    DBCC DLL_name (مجاني).
  • يتم تنفيذ الإجراء المخزن الموسع بنفس طريقة تنفيذ الإجراء المخزن العادي:
    تنفيذ xp_extenedProcName @param1، @param2 OUTPUT
    @param1 معلمة الإدخال
    @param2 معلمة الإدخال/الإخراج
انتباه!
نظرًا لأنه يتم تنفيذ الإجراءات المخزنة الموسعة في مساحة العنوان لعملية خدمة MS SQL Server، فإن أي أخطاء فادحة تحدث في تشغيلها يمكن أن تؤدي إلى تعطيل قلب الخادم، لذلك يوصى باختبار ملف DLL الخاص بك بدقة قبل تثبيته على خادم إنتاج.

إنشاء الإجراءات المخزنة الموسعة.

الإجراء المخزن الموسع هو دالة تحتوي على النموذج الأولي التالي:

SRVRETCODE xp_extenedProcName(SRVPROC * pSrvProc);

معامل pSrvProcمؤشر إلى بنية SRVPROC، وهو مؤشر لكل اتصال عميل محدد. الحقول الموجودة في هذه البنية غير موثقة وتحتوي على معلومات تستخدمها مكتبة ODS لإدارة الاتصالات والبيانات بين تطبيق خادم Open Data Services والعميل. على أية حال، لا تحتاج إلى الوصول إلى هذه البنية، ناهيك عن تعديلها. يجب تحديد هذه المعلمة عند استدعاء أي وظيفة ODS API، لذلك لن أتناول وصفها أكثر.
يعد استخدام البادئة xp_ أمرًا اختياريًا، ولكن هناك اصطلاحًا لبدء اسم الإجراء المخزن الموسع بهذه الطريقة لتمييزه عن الإجراء المخزن العادي، والذي، كما تعلم، يبدأ أسماؤه بالبادئة sp_.
يجب أن تتذكر أيضًا أن أسماء الإجراءات المخزنة الموسعة حساسة لحالة الأحرف. لا تنس ذلك عند استدعاء إجراء مخزن موسع، وإلا فسوف تتلقى رسالة خطأ بدلاً من النتيجة المتوقعة.
إذا كنت بحاجة إلى كتابة رمز تهيئة/إلغاء التهيئة لـ dll، استخدم الدالة DllMain() القياسية لهذا الغرض. إذا لم تكن لديك مثل هذه الحاجة، ولا تريد كتابة DLLMain()، فسيقوم المترجم ببناء نسخته الخاصة من وظيفة DLLMain()، والتي لا تفعل شيئًا سوى إرجاع TRUE. يجب الإعلان عن كافة الوظائف التي يتم استدعاؤها من ملف dll (أي الإجراءات المخزنة الموسعة) على أنها قابلة للتصدير. إذا كنت تكتب في MS Visual C++، استخدم التوجيه __declspec(dllexport). إذا كان برنامج التحويل البرمجي الخاص بك لا يدعم هذا التوجيه، قم بوصف الوظيفة المصدرة في قسم الصادرات من ملف DEF.
لذلك، لإنشاء مشروع، سنحتاج إلى الملفات التالية:

  • يحتوي ملف الرأس Srv.h على وصف لوظائف ODS API ووحدات الماكرو؛
  • Opends60.lib هو ملف استيراد لمكتبة Opends60.dll، التي تنفذ الخدمة بأكملها التي تقدمها ODS API.
توصي Microsoft بشدة بأن تقوم كافة مكتبات الارتباط الحيوي (DLL) التي تنفذ الإجراءات المخزنة الموسعة بتصدير الوظيفة:

ديكلسبيك(dllexport) أولونج __GetXpVersion()
{
إرجاع ODS_VERSION؛
}

عندما يقوم MS SQL Server بتحميل ملف DLL مع إجراء مخزن موسع، فإنه يستدعي هذه الوظيفة أولاً للحصول على معلومات حول إصدار المكتبة المستخدمة.

لكتابة أول إجراء مخزن موسع، ستحتاج إلى تثبيت ما يلي على جهاز الكمبيوتر الخاص بك:

MS SQL Server 2000 من أي إصدار (لدي إصدار شخصي). أثناء عملية التثبيت، تأكد من تحديد خيار العينة المصدر
- MS Visual C++ (لقد استخدمت الإصدار 7.0)، ولكنني أعلم بالتأكيد أن الإصدار 6.0 سيفي بالغرض

يلزم تثبيت SQL Server -a لاختبار ملف DLL وتصحيح أخطائه. من الممكن أيضًا تصحيح الأخطاء عبر الشبكة، لكنني لم أفعل ذلك مطلقًا، لذلك قمت بتثبيت كل شيء على القرص المحلي الخاص بي. يتضمن Microsoft Visual C++ 7.0 Interprise Edition معالج DLL للإجراءات المخزنة الموسعة. من حيث المبدأ، فهو لا يفعل أي شيء طبيعي للغاية، ولكنه يقوم فقط بإنشاء قالب قالب لإجراء مخزن ممتد. إذا كنت تحب الماجستير، يمكنك استخدامه. أفضل أن أفعل كل شيء يدويًا، وبالتالي لن أفكر في هذه الحالة.

والآن إلى النقطة:
- إطلاق Visual C++ وإنشاء مشروع جديد - مكتبة الارتباط الديناميكي Win32.
- تضمين ملف رأس في المشروع - #include ;
- انتقل إلى قائمة الأدوات => الخيارات وأضف مسارات البحث لملفات التضمين والمكتبة. إذا لم تقم بتغيير أي شيء عند تثبيت MS SQL Server، فحدد:

C:Program FilesMicrosoft SQL Server80ToolsDevToolsInclude لملفات الرأس؛
- C:Program FilesMicrosoft SQL Server80ToolsDevToolsLib لملفات المكتبة.
- حدد اسم ملف المكتبة opends60.lib في خيارات الرابط.

عند هذه النقطة، تكتمل المرحلة التحضيرية، ويمكنك البدء في كتابة أول إجراء مخزن موسع لك.

صياغة المشكلة.

قبل أن تبدأ البرمجة، يجب أن يكون لديك فكرة واضحة عن أين تبدأ، وما هي النتيجة النهائية، وكيفية تحقيقها. لذا، إليك المواصفات الفنية:

قم بتطوير إجراء مخزن موسع لـ MS SQL Server 2000 يتلقى قائمة كاملة بالمستخدمين المسجلين في المجال ويعيدها إلى العميل في شكل مجموعة سجلات قياسية. باعتبارها معلمة الإدخال الأولى، تتلقى الوظيفة اسم الخادم الذي يحتوي على قاعدة بيانات Active Directory، أي اسم وحدة تحكم المجال. إذا كانت هذه المعلمة فارغة، فيجب تمرير قائمة المجموعات المحلية إلى العميل. سيتم استخدام المعلمة الثانية بواسطة الإجراء المخزن الموسع لإرجاع قيمة نتيجة العملية الناجحة/غير الناجحة (معلمة OUTPUT). إذا تم إكمال الإجراء المخزن الموسع بنجاح، فمن الضروري تمرير عدد السجلات التي تم إرجاعها إلى مجموعة سجلات العميل، وإذا لم يكن من الممكن الحصول على المعلومات المطلوبة أثناء العملية، فيجب تعيين قيمة المعلمة الثانية على - 1، كعلامة على الانتهاء غير الناجح.

النموذج الأولي الشرطي للإجراء المخزن الموسع هو كما يلي:

xp_GetUserList(@NameServer varchar, @CountRec int OUTPUT);


وإليك قالب الإجراء المخزن الموسع الذي نحتاج إلى ملؤه بالمحتوى:

#يشمل
#يشمل
#تعريف XP_NOERROR 0
#تعريف XP_ERROR -1


__declspec(dllexport) رمز الخادم xp_GetGroupList(SRVPROC* pSrvProc)
{

// التحقق من عدد المعلمات التي تم تمريرها

// التحقق من نوع المعلمات التي تم تمريرها

// التحقق مما إذا كانت المعلمة 2 هي معلمة الإخراج

// التحقق مما إذا كانت المعلمة 2 طويلة بما يكفي لتخزين القيمة

// الحصول على معلمات الإدخال

// الحصول على قائمة المستخدمين

// إرسال البيانات المستلمة إلى العميل في شكل مجموعة سجلات قياسية

// تعيين قيمة معلمة الإخراج

العودة (XP_NOERROR)؛
}


العمل مع معلمات الإدخال

في هذا الفصل، لا أريد تشتيت انتباهك على أشياء غريبة، ولكن أريد التركيز على العمل مع المعلمات التي تم تمريرها إلى الإجراء المخزن الموسع. لذلك، سنقوم بتبسيط مواصفاتنا الفنية إلى حد ما وتطوير ذلك الجزء منها فقط الذي يعمل مع معلمات الإدخال. لكن أولاً، ليس هناك الكثير من النظرية

الإجراء الأول الذي يجب أن يقوم به الإجراء المخزن الموسع الخاص بنا هو تلقي المعلمات التي تم تمريرها إليه عند استدعائه. باتباع الخوارزمية المذكورة أعلاه، نحتاج إلى تنفيذ الخطوات التالية:

تحديد عدد المعلمات التي تم تمريرها؛
- التأكد من أن المعلمات التي تم تمريرها لها نوع البيانات الصحيح؛
- تأكد من أن معلمة OUTPUT المحددة ذات طول كافٍ لتخزين القيمة التي تم إرجاعها بواسطة الإجراء المخزن الموسع الخاص بنا.
- تلقي المعلمات التي تم تمريرها.
- قم بتعيين قيم معلمات الإخراج كنتيجة للإكمال الناجح/غير الناجح للإجراء المخزن الموسع.

الآن دعونا ننظر إلى كل نقطة بالتفصيل:

تحديد عدد المعلمات التي تم تمريرها إلى إجراء مخزن موسع

للحصول على عدد المعلمات التي تم تمريرها، يجب عليك استخدام الدالة:

int srv_rpcparams(SRV_PROC * srvproc);


في حالة نجاحها، تقوم الدالة بإرجاع عدد المعلمات التي تم تمريرها إلى الإجراء المخزن الموسع. إذا تم استدعاء الإجراء المخزن الموسع بدون معلمات، فسوف يُرجع srv_rpcparams -1. يمكن تمرير المعلمات بالاسم أو بالمنصب (بدون اسم). وعلى أية حال، لا ينبغي الخلط بين هاتين الطريقتين. ستؤدي محاولة تمرير معلمات الإدخال إلى دالة بالاسم والموضع في نفس الوقت إلى حدوث خطأ، وسيُرجع srv_rpcparams القيمة 0.

تحديد نوع البيانات وطول المعلمات التي تم تمريرها

للحصول على معلومات حول نوع المعلمات التي تم تمريرها وطولها، توصي Microsoft باستخدام الدالة srv_paramifo. تحل هذه الوظيفة العامة محل استدعاءات srv_paramtype وsrv_paramlen وsrv_parammaxlen، والتي تم إهمالها الآن. هنا هو النموذج الأولي الخاص به:

إنت srv_paraminfo(
SRV_PROC * سرفبروك،
كثافة العمليات ن,
بايت * نوع pb،
أولونج * ثنائي الفينيل متعدد الكلور ماكسلين،
أولونج * pcbActualLen،
بايت * ببداتا،
BOOL * pfNull);

بي بايتمؤشر إلى متغير يتلقى معلومات حول نوع معلمة الإدخال؛
pbTypeيحدد الرقم التسلسلي للمعلمة. يبدأ رقم المعلمة الأولى من 1.
pcbMaxLenمؤشر إلى متغير تقوم فيه الدالة بتخزين الحد الأقصى لقيمة طول المعلمة. يتم تحديد هذه القيمة حسب نوع البيانات المحدد للمعلمة التي تم تمريرها، وسنستخدمها للتأكد من أن معلمة OUTPUT ذات طول كافٍ لتخزين البيانات التي يتم تمريرها.
pcbActualLenمؤشر إلى الطول الحقيقي للمعلمة التي تم تمريرها إلى الإجراء المخزن الموسع عند استدعائها. إذا كان طول المعلمة التي تم تمريرها صفرًا وتم تعيين علامة pfNull على FALSE، فإن (* pcbActualLen) ==0.
pbData- مؤشر إلى المخزن المؤقت الذي يجب تخصيص الذاكرة له قبل استدعاء srv_paraminfo. في هذا المخزن المؤقت، تضع الدالة معلمات الإدخال المستلمة من الإجراء المخزن الموسع. حجم المخزن المؤقت بالبايت يساوي قيمة pcbMaxLen. إذا تم تعيين هذه المعلمة على NULL، فلن تتم كتابة أي بيانات إلى المخزن المؤقت، ولكن تقوم الدالة بإرجاع القيم بشكل صحيح *pbType، *pcbMaxLen، *pcbActualLen، *pfNull. لذلك، تحتاج إلى الاتصال بـ srv_paraminfo مرتين: أولاً باستخدام pbData=NULL، ثم بعد تخصيص حجم الذاكرة المطلوبة لمخزن مؤقت يساوي pcbActualLen، اتصل بـ srv_paraminfo مرة ثانية، بتمرير مؤشر إلى كتلة الذاكرة المخصصة إلى pbData.
pfNullالمؤشر إلى علامة NULL. يقوم srv_paraminfo بتعيينه على TRUE إذا كانت قيمة معلمة الإدخال فارغة.

التحقق مما إذا كانت معلمة OUTPUT الثانية هي معلمة.

تم تصميم الدالة srv_paramstatus()‎ لتحديد حالة المعلمة التي تم تمريرها:

إنت srv_paramstatus (
SRV_PROC * سرفبروك،
كثافة العمليات ن
);

n هو رقم المعلمة التي تم تمريرها إلى الإجراء المخزن الموسع عند استدعائها. اسمحوا لي أن أذكرك: يتم ترقيم المعلمات دائمًا بدءًا من 1.
لإرجاع قيمة، يستخدم srv_paramstatus البت صفر. إذا تم تعيينها على 1، فإن المعلمة التي تم تمريرها هي معلمة OUTPUT، وإذا تم تعيينها على 0، فهي معلمة عادية تم تمريرها حسب القيمة. إذا تم استدعاء الإجراء المخزن الممتد بدون معلمات، فسترجع الدالة -1.

تحديد قيمة معلمة الإخراج.

يمكن إعطاء قيمة لمعلمة الإخراج التي تم تمريرها إلى المعلمة المخزنة الموسعة باستخدام وظيفة srv_paramsetoutput. تحل هذه الوظيفة الجديدة محل استدعاء الدالة srv_paramset، والذي تم إهماله الآن بسبب لا يدعم أنواع البيانات الجديدة المقدمة في واجهة برمجة تطبيقات ODS والبيانات ذات الطول الصفري.

إنت srv_paramsetoutput(
SRV_PROC * سرفبروك،
كثافة العمليات ن,
بايت *pbData،
أولونج سي بي لين,
منطقية فارغة
);

نالرقم التسلسلي للمعلمة التي سيتم تعيين القيمة الجديدة لها. يجب أن تكون هذه معلمة OUTPUT.
pbDataمؤشر إلى مخزن مؤقت يحتوي على البيانات التي سيتم إرسالها إلى العميل لتعيين قيمة معلمة الإخراج.
cbLenطول المخزن المؤقت للبيانات المرسلة. إذا كان نوع بيانات المعلمة التي تم تمريرها إلى OUTPUT يحدد بيانات ذات طول ثابت ولا يسمح بتخزين قيمة NULL (على سبيل المثال، SRVBIT أو SRVINT1)، فإن الدالة تتجاهل المعلمة cbLen. يشير cbLen=0 إلى بيانات ذات طول صفري، ويجب تعيين fNull إلى FALSE.
خاليةاضبط هذا على TRUE إذا كان من الضروري تعيين معلمة الإرجاع على NULL، ويجب أن تكون قيمة cbLen 0 وإلا ستفشل الوظيفة. في جميع الحالات الأخرى fNull=FALSE.
في حالة نجاحها، ترجع الدالة SUCCEED. إذا كانت قيمة الإرجاع هي FAIL، فهذا يعني فشل الاستدعاء. كل شيء بسيط وواضح
الآن نحن نعرف ما يكفي لكتابة أول إجراء مخزن موسع لدينا، والذي سيعيد قيمة من خلال المعلمة التي تم تمريرها إليها، دع هذه تكون السلسلة Hello World! يمكن تنزيل نسخة تصحيح الأخطاء من المثال هنا.

#يشمل

#تعريف XP_NOERROR 0
#تعريف XP_ERROR 1

#تعريف MAX_SERVER_ERROR 20000
#تعريف XP_HELLO_ERROR MAX_SERVER_ERROR+1

خطأ طباعة باطلة (SRV_PROC*، CHAR*)؛

#ifdef __cplusplus
الخارجي "ج" (
#إنهاء إذا

SRVRETCODE __declspec(dllexport) xp_helloworld(SRV_PROC* pSrvProc);

#ifdef __cplusplus
}
#إنهاء إذا

SRVRETCODE xp_helloworld(SRV_PROC* pSrvProc)
{
char szText = "مرحبا بالعالم!";
بايت bType؛
ULONG cbMaxLen;
ULONG cbActualLen;
منطقية fNull؛

/* تحديد عدد المنقولين إلى وحدة التخزين الموسعة
إجراء المعلمة */
إذا (srv_rpcparams(pSrvProc) != 1)
{
printError(pSrvProc, "عدد المعلمات غير صالح!");
العودة (XP_ERROR)؛
}

/* الحصول على معلومات حول نوع البيانات وطول المعلمات التي تم تمريرها */
إذا (srv_paraminfo(pSrvProc, 1, &bType, &cbMaxLen,
&cbActualLen، NULL، &fNull) == فشل)
{
خطأ الطباعة (بسرفبروك،
""غير قادر على الحصول على معلومات حول معلمات الإدخال...");
العودة (XP_ERROR)؛
}

/* تحقق مما إذا كانت معلمة OUTPUT التي تم تمريرها هي معلمة */
إذا ((srv_paramstatus(pSrvProc, 1) & SRV_PARAMRETURN) == FAIL)
{
خطأ الطباعة (بسرفبروك،
"المعلمة التي تم تمريرها ليست معلمة OUTPUT!");
العودة (XP_ERROR)؛
}

/* التحقق من نوع بيانات المعلمة التي تم تمريرها */
إذا (bType != SRVBIGVARCHAR && bType != SRVBIGCHAR)
{
printError (pSrvProc، "نوع المعلمة التي تم تمريرها غير صحيح!")؛
العودة (XP_ERROR)؛
}

/* تأكد من أن المعلمة التي تم تمريرها طويلة بما يكفي لتخزين السلسلة التي تم إرجاعها */
إذا (cbMaxLen< strlen(szText))
{
خطأ الطباعة (بسرفبروك،
""المعلمة التي تم تمريرها ليست ذات طول كافٍ لتخزين السلسلة n التي تم إرجاعها!");
العودة (XP_ERROR)؛
}

/* قم بتعيين قيمة معلمة الإخراج */
إذا (FAIL == srv_paramsetoutput(pSrvProc, 1, (BYTE*)szText, 13, FALSE))
{
خطأ الطباعة (بسرفبروك،
"لا يمكنني تعيين قيمة معلمة الإخراج...");
العودة (XP_ERROR)؛
}

srv_senddone(pSrvProc, (SRV_DONE_COUNT | SRV_DONE_MORE), 0, 1);
العودة (XP_NOERROR)؛
}

خطأ طباعة فارغ (SRV_PROC *pSrvProc، CHAR* szErrorMsg)
{
srv_sendmsg(pSrvProc, SRV_MSG_ERROR, XP_HELLO_ERROR, SRV_INFO, 1,
NULL, 0, 0, szErrorMsg,SRV_NULLTERM);

Srv_senddone(pSrvProc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
}

ظلت الوظيفتان srv_sendmsg وsrv_senddone دون النظر فيهما. يتم استخدام الدالة srv_sendmsg لإرسال الرسائل إلى العميل. هنا هو النموذج الأولي الخاص به:

إنت srv_sendmsg (
SRV_PROC * سرفبروك،
نوع الرسالة int,
رسالة DBINT،
فئة دبتينينت
حالة دبتينينت،
دبشار * اسم rpc،
إنت rpcnamelen,
DBUSMALLINT لينوم,
دبشار * الرسالة،
int msglen
);

msgtypeتحديد نوع الرسالة المرسلة إلى العميل. يشير الثابت SRV_MSG_INFO إلى رسالة معلومات، ويشير SRV_MSG_ERROR إلى رسالة خطأ؛
رقم الرسالة msgnum؛
فصل- خطورة الخطأ الذي حدث. تحتوي رسائل المعلومات على قيمة خطورة أقل من أو تساوي 10؛
ولايةرقم حالة الخطأ للرسالة الحالية. توفر هذه المعلمة معلومات حول سياق الخطأ الذي حدث. تتراوح القيم الصالحة من 0 إلى 127؛
rpcname غير مستخدم حاليًا؛
rpcnamelen - غير مستخدم حاليًا؛
Linenumهنا يمكنك تحديد رقم السطر للكود المصدر. وبناء على هذه القيمة، سيكون من السهل فيما بعد تحديد مكان حدوث الخطأ. إذا كنت لا تريد استخدام هذه الميزة، فاضبط قيمة الخط على 0؛
مؤشر الرسالة إلى سلسلة مرسلة إلى العميل؛
msglenيحدد الطول بالبايت لسلسلة الرسالة. إذا انتهت هذه السلسلة بحرف فارغ، فيمكن تعيين قيمة هذه المعلمة إلى SRV_NULLTERM.
قيم الإرجاع:
- إذا نجحت نجحت
- إذا فشل الفشل.

أثناء التشغيل، يجب أن يقوم الإجراء المخزن الموسع بالإبلاغ عن حالته بانتظام إلى تطبيق العميل، أي. إرسال رسائل حول الإجراءات المكتملة. هذا ما تم تصميم الدالة srv_senddone من أجله:

كثافة العمليات srv_senddone(
SRV_PROC * سرفبروك،
حالة ديبو سمالينت،
معلومات ديبو سمالينت،
عدد DBINT
);

علامة حالة الحالة. يمكن تعيين قيمة هذه المعلمة باستخدام العوامل المنطقية AND وOR لدمج الثوابت الواردة في الجدول:
وصف علامة الحالة
SRV_DONE_FINAL مجموعة النتائج الحالية نهائية؛
SRV_DONE_MORE مجموعة النتائج الحالية ليست نهائية؛ يجب توقع الدفعة التالية من البيانات؛
SRV_DONE_COUNT تحتوي معلمة العدد على قيمة صالحة
SRV_DONE_ERROR يستخدم للتنبيه عند حدوث الأخطاء وإنهائها على الفور.
داخلمحفوظة، يجب ضبطها على 0.
العد هو عدد مجموعات النتائج المرسلة إلى العميل. إذا تم تعيين علامة الحالة على SRV_DONE_COUNT، فيجب أن يحتوي العدد على العدد الصحيح لمجموعة السجلات المرسلة إلى العميل.
قيم الإرجاع:
- إذا نجحت نجحت
- إذا فشل الفشل.

تثبيت الإجراءات المخزنة الموسعة على MS SQL Server 2000

1. انسخ مكتبة dll مع الإجراء المخزن الموسع إلى دليل binn على الجهاز المثبت عليه MS SQL Server. المسار الخاص بي هو كما يلي: C:Program FilesMicrosoft SQL ServerMSSQLBinn؛
2. قم بتسجيل الإجراء المخزن الموسع على الخادم عن طريق تنفيذ البرنامج النصي التالي:

استخدام ماستر
تنفيذ SP_ADDEXTENDEDPROC xp_helloworld، xp_helloworld.dll

اختبر xp_helloworld عن طريق تشغيل البرنامج النصي التالي:

أعلن @Param varchar(33)
تنفيذ xp_helloworld @Param OUTPUT
حدد @Param AS OUTPUT_Param


خاتمة

وبهذا ينتهي الجزء الأول من مقالتي. الآن أنا متأكد من أنك جاهز للتعامل مع مواصفاتنا الفنية بنسبة 100%. وفي المقالة التالية ستتعلم:
- أنواع البيانات المحددة في واجهة برمجة تطبيقات ODS؛
- ميزات تصحيح الإجراءات المخزنة الموسعة؛
- كيفية إنشاء مجموعات السجلات ونقلها إلى تطبيق العميل؛
- سننظر جزئيًا في وظائف Active Directory Network Manegment API اللازمة للحصول على قائمة مستخدمي المجال؛
- سنقوم بإنشاء مشروع نهائي (سنقوم بتنفيذ المواصفات الفنية لدينا)
أتمنى أن أراك قريبا!

ملاحظة: قم بتنزيل ملفات الأمثلة للمقالة الخاصة بـ Studio 7.0