برمجة إكسيلتحليل البيانات

VBA: كيفية فرز ورقة العمل حسب أعمدة متعددة

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

Mohammed looti أكاديمي وباحث متخصص في علم النفس
تاريخ النشر
تمت المراجعة العلمية · د. مروة عبد العظيم · 12 سبتمبر، 2026
مراجعة وتدقيق علمي معتمد تاريخ التدقيق: 12 سبتمبر، 2026
د. مروة عبد العظيم دكتوراه
أستاذة علم النفس جامعة كربلاء
معايير التدقيق والاعتماد السريري

يخضع هذا المحتوى لمعايير ضبط الجودة والتدقيق العلمي والأكاديمي الصارمة في شبكة علم النفس العربي، لضمان صحة المعلومات ودقتها السريرية ومطابقتها لأحدث الأدلة والبراهين الصادرة عن الجمعيات النفسية والطبية المعتمدة (APA / WHO).

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

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

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

1. مقدمة تأسيسية حول أتمتة عمليات الفرز في إكسيل باستخدام لغة VBA

1.1 مفهوم المعالجة الآلية للبيانات وجدواها التحليلية

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

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

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

1.2 التطور المعماري لأدوات الفرز داخل بيئة مايكروسوفت إكسيل

يقوم نموذج كائنات إكسيل (Excel Object Model) على فصل دقيق بين الواجهة الرسومية التفاعلية وبين المحرك البرمجي الداخلي الذي يتحكم في السلوكيات الوظيفية للتطبيق. فبينما يقتصر تعامل المستخدم العادي مع مربعات الحوار البسيطة لفرز الأعمدة، توفر لغة VBA للمطور قدرة استثنائية على النفاذ المباشر إلى خصائص النطاقات والخلايا، وتوجيه مسارات المعالجة على المستوى الحسابي الدقيق.

وقد شهدت بنية أدوات الفرز تطوراً معمارياً ملحوظاً عبر إصدارات مايكروسوفت إكسيل المتعاقبة. ففي الإصدارات الكلاسيكية، اعتمدت البيئة البرمجية بشكل مطلق على تعليمة Range.Sort، وهي دالة تنفيذية مباشرة وموجزة تتيح الترتيب السريع للنطاقات بالاعتماد على ثلاثة مفاتيح فرز كحد أقصى (Key1, Key2, Key3). ومع إطلاق مايكروسوفت أوفيس 2007، أدخلت الشركة نموذجاً برمجياً حديثاً يتمحور حول كائن SortFields التابع لكائن الفرز العام في ورقة العمل (Worksheet.Sort)، بهدف التغلب على قيود المفاتيح الثلاثة وفتح المجال أمام عدد غير محدود من معايير الفرز المتداخلة.

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

1.3 المتطلبات المسبقة لإعداد بيئة التطوير المتكاملة (VBE)

يتطلب الشروع في كتابة وتطوير أكواد لغة VBA تهيئة ملائمة لبيئة التطوير المتكاملة (Visual Basic Editor – VBE). وتبدأ هذه العملية بتفعيل تبويب المطور (Developer Tab) داخل الشريط الرئيسي لبرنامج إكسيل، والذي يكون معطلاً في التثبيت الافتراضي للحزمة البرمجية لحماية المستخدمين العاديين من التعقيدات التقنية. ويمكن تنشيطه بسهولة عبر خيارات إكسيل وتخصيص الشريط، مما يفتح الباب للوصول إلى أدوات الماكرو ونافذة محرر الأكواد عبر الاختصار الشهير (Alt + F11).

كما تبرز المسألة الأمنية بوصفها محددًا محوريًا لتشغيل الأكواد البرمجية، حيث تضع أنظمة مايكروسوفت الحديثة قيوداً صارمة على تشغيل وحدات الماكرو لحماية الأجهزة من البرمجيات الخبيثة. ويتعين على المطور ضبط إعدادات مركز التوثيق (Trust Center Settings) للسماح بتشغيل الأكواد الموثوقة أو الرقمية، وتعيين المجلدات الآمنة لحفظ المصنفات البرمجية ذات الامتداد الخاص (.xlsm أو .xlsb) التي تدعم استضافة النصوص البرمجية وتنفيذها دون اعتراضات تشغيلية.

داخل محرر Visual Basic، ينبغي للمطور تنظيم التعليمات البرمجية ضمن وحدات برمجية قياسية (Standard Modules) يتم إدراجها داخل المشروع، والابتعاد عن كتابة الأكواد التشغيلية العامة داخل كائنات أوراق العمل المستقلة (Sheet Objects) إلا إذا كانت مرتبطة بأحداث تفاعلية محددة. كما تقتضي أصول العمل الأكاديمي والبرمجي الالتزام بتوثيق الشفرة من خلال التعليقات الإيضاحية (Comments) المبدوءة بعلامة الفاصلة العليا المقتبسة، مما يسهل عمليات المراجعة، والتدقيق، وتحديث الكود في المستقبل من قِبل مطورين آخرين.

2. البنية التركيبية الأساسية لتعليمة Range.Sort في لغة VBA

2.1 تشريح الوسائط الأساسية لدالة الفرز الكلاسيكية

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

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

وللحفاظ على وضوح الكود وسهولة قراءته داخل بيئة التطوير، يُنصح بربط الوسائط المتعددة لدالة الفرز عبر استخدام الشرطة السفلية (Underscore _) التي تسمح بتقسيم السطر البرمجي الطويل إلى عدة أسطر متتالية دون إحداث خطأ تركيبي في تصريف اللغة، مع تحديد أسماء الوسائط بصورة صريحة مقترنة بعلامة الإسناد النقطية (:=)، مثل:

Range(“A1:C50”).Sort Key1:=Range(“A1”), Order1:=xlAscending, Key2:=Range(“B1”), Order2:=xlDescending, Header:=xlYes

2.2 إسناد المعلمات المكانية لنطاقات الفرز

تتطلب برمجة الفرز دقة مكانية متناهية عند تعيين مراجع النطاقات وخلايا المفاتيح. ومن الأخطاء الشائعة التي يقع فيها بعض المطورين المبتدئين تمرير نطاق كامل من صفوف متعددة كوسيط للمفتاح (مثل Key1:=Range(“A2:A100”))، في حين أن المحرك الداخلي لـ VBA يحتاج فقط إلى الإشارة إلى خلية البداية في ذلك العمود، أو رأس العمود، ليكتشف تلقائياً الاتجاه الرأسي للقيم المعنية. وبالتالي، يكفي تمرير Range(“A1”) أو Range(“A2”) كمفتاح لفرز العمود A بأكمله ضمن النطاق العام المحدد.

إضافة إلى ذلك، يجب الحذر الشديد من عدم تطابق الأبعاد المكانية بين النطاق المستهدف للفرز وبين السجلات الفعلية للجداول المجاورة. فإذا اشتمل الجدول على خمسة أعمدة (من A إلى E)، وقام المبرمج بتوجيه أمر الفرز إلى النطاق Range(“A1:C100”) فقط، فإن النتيجة الحتمية ستكون إعادة ترتيب الأعمدة الثلاثة الأولى مع بقاء العمودين D وE ثابتين في مواقعهما الأصلية، مما يؤدي إلى تدمير النزاهة الهيكلية للبيانات واختلاط سجلات الصفوف ببعضها البعض بصورة لا يمكن التراجع عنها إلا بإغلاق المصنف دون حفظ.

تفرض الخلايا المدمجة (Merged Cells) تحدياً تقنياً حرجاً في هذه البنية، حيث يمنع محرك إكسيل عمليات الفرز التي تتضمن نطاقات تحتوي على خلايا مدمجة ذات أحجام غير متطابقة. ويتسبب وجود خلية مدمجة واحدة ضمن النطاق في إطلاق الخطأ البرمجي الشهير (Runtime Error 1004). ولتأمين استقرار العملية البرمجية، ينبغي دائماً إلغاء دمج الخلايا واستبدال التنسيق المدمج بخاصية المحاذاة عبر التحديد (Center Across Selection)، مع التأكد من إحاطة النطاق بالكامل ضمن مستطيل متماسك وخالٍ من الانقطاعات المكانية المشوهة.

3. معايير التوجيه والترتيب: الفرز التصاعدي والتنازلي

3.1 التحكم في وسائط الاتجاه عبر الثوابت المعرفة مسبقاً

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

تتجلى قوة تعليمة Range.Sort في قدرتها على التوفيق والمزاوجة التامة بين اتجاهات الترتيب المختلفة لكل مفتاح على حدة. فيمكن للمطور بكل سلاسة توجيه الكود لفرز المفتاح الأول (Key1) تصاعدياً عبر الوسيطة Order1:=xlAscending، ثم توجيه المفتاح الثاني (Key2) للترتيب تنازلياً عبر Order2:=xlDescending، ثم العودة للمفتاح الثالث (Key3) بفرز تصاعدي عبر Order3:=xlAscending. يتيح هذا التناغم تلبية المتطلبات الإحصائية المعقدة بدقة ميكانيكية مطلقة.

في حال أغفل المطور تحديد وسيطة الاتجاه وأسقط Order1 أو Order2 من التركيب البرمجي، فإن محرك VBA يلجأ إلى السلوك الافتراضي المعرف في النظام وهو xlAscending (الترتيب التصاعدي). ورغم أن الكود سينفذ دون أخطاء في هذه الحالة، إلا أن أصول البرمجة الاحترافية تحتم التصريح الصريح عن وسائط الاتجاه منعاً للالتباسات الذهنية وضماناً لقراءة وفهم منطق الكود بصورة فورية من قِبل أي طرف خارجي.

3.2 المنطق التراتبي المزدوج في تحليل البيانات المتداخلة

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

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

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

4. الإدارة المنهجية لصف العناوين باستخدام الوسيطة Header

4.1 خيارات المعلمة xlYes وxlNo وتطبيقاتها العملية

تمثل وسيطة صف العناوين (Header) عنصراً حاسماً في استقرار عمليات الفرز الآلية، حيث تخبر محرك لغة VBA بكيفية التعامل مع الصف العلوي الأول من النطاق المستهدف. وتوفر البيئة البرمجية ثلاثة ثوابت رئيسية للتحكم في هذه المعلمة: الثابت الأول هو xlYes، الذي يوجه المحرك لاعتبار الصف الأول بمثابة ترويسة أو رأس للجدول تحتوي على مسميات الحقول فقط، ومن ثم يتم تجميده واستبعاده تماماً من خوارزمية الفرز، مع استخدامه كمرجع لعنونة البيانات المندرجة تحته.

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

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

4.2 الآثار الهيكلية لاختيار حالة الترويسة على دقة النتائج

تعد مشكلة هبوط رأس الجدول إلى منتصف البيانات المفرزة (Header Infiltration) من أكثر المشكلات التقنية شيوعاً وإحراجاً للمطورين، وهي تنتج عادة عن تمرير xlNo سهواً أو ترك المعلمة فارغة ليلجأ النظام إلى التخمين الخاطئ. وتتفاقم هذه المشكلة عندما تحتوي الترويسة على نصوص تبدأ بحروف تقع في وسط الأبجدية، مما يمزق الجدول إلى شطرين ويجعل عمليات البحث والاسترجاع المرجعي اللاحقة عبر دوال مثل VLOOKUP أو XLOOKUP تسفر عن مخرجات تالفة أو غير منطقية.

لضمان الفصل الهيكلي الحاسم، ينصح الخبراء بفرض تباين بصري ورقمي صريح بين ترويسة الجدول والخلايا التابعة له. يشمل ذلك استخدام أنماط خطوط عريضة (Bold)، أو ألوان خلفيات مميزة، أو تنسيقات حدود واضحة لصف العناوين، إذ تعزز هذه الممارسات من استقرار خوارزميات التعرف المرجعي، حتى وإن كان المبرمج يعتمد التعيين الإجباري والصريح لوسيطة Header:=xlYes في كافة الأكواد المكتوبة.

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

5. تطبيق عملي: فرز بيانات أداء الفرق الرياضية ونقاط اللاعبين

5.1 بناء النموذج التطبيقي وهيكلة البيانات الافتراضية

لترسيخ المفاهيم النظرية التي تم استعراضها، سنقوم بتطبيق نموذج عملي شامل يحاكي بيئة تحليل الأداء الرياضي لبطولة دوري كرة القدم أو كرة السلة. يتكون النموذج من جدول إحصائي يمتد في ورقة العمل ضمن النطاق الميداني A1:C11، بحيث يمثل العمود A اسم “الفريق” (Team Name)، ويمثل العمود B اسم “اللاعب” (Player Name)، بينما يمثل العمود C “مجموع النقاط المحرزة” (Total Points). وتوفر هذه الهيكلية بيئة مثالية لاختبار الفرز متعدد المعايير القائم على أعمدة متباينة في طبيعتها النوعية والكمية.

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

ولضمان دقة الاختبار واكتمال فحص خوارزمية VBA، تم تعمد إدراج حالات تكرار متطابقة لأسماء الفرق الرياضية داخل العمود A (مثل وجود أربعة لاعبين ينتمون لنفس الفريق)، بالإضافة إلى تباين درجات النقاط في العمود C لاختبار استجابة المفتاح الثاني. ويوضح الجدول الافتراضي المرجعي التالي تركيبة البيانات قبل تطبيق كود الماكرو البرمجي:

  • الصف 1 (الترويسة): الفريق (A1) | اللاعب (B1) | النقاط (C1)
  • الصف 2: الهلال | سالم | 25
  • الصف 3: النصر | رونالدو | 35
  • الصف 4: الاتحاد | بنزيما | 22
  • الصف 5: الهلال | ميتروفيتش | 28
  • الصف 6: النصر | تاليسكا | 20
  • الصف 7: الأهلي | محرز | 18
  • الصف 8: الهلال | مالكوم | 15
  • الصف 9: النصر | ماني | 19
  • الصف 10: الأهلي | فيرمينو | 12
  • الصف 11: الاتحاد | حمدالله | 22

5.2 كتابة وتنفيذ إجراء SortMultipleColumns النموذجي

لترجمة هذه المتطلبات إلى إجراء برمجي تنفيذي، نفتح محرر Visual Basic وننشئ وحدة برمجية جديدة (Module1)، ثم نصيغ الإجراء المسمى SortMultipleColumns. يعتمد هذا الإجراء على كائن النطاق Range(“A1:C11”) كمجال كلي للفرز، مع إسناد المفتاح الرئيسي Key1 للخلية A1 لتمثيل عمود الفريق، وتوجيه اتجاهه تصاعدياً بواسطة xlAscending، بينما يسند المفتاح الثانوي Key2 للخلية C1 لتمثيل عمود النقاط، ويوجه تنازلياً بواسطة xlDescending.

تأتي صياغة الكود خطوة بخطوة على النحو التالي:

Sub SortMultipleColumns()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets(“Sheet1”)
    
    With ws
        .Range(“A1:C11”).Sort _
            Key1:=.Range(“A1”), Order1:=xlAscending, _
            Key2:=.Range(“C1”), Order2:=xlDescending, _
            Header:=xlYes
    End With
End Sub

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

5.3 تفكيك آليات المعالجة الداخلية أثناء تشغيل الماكرو

عندما يستقبل محرك VBA أمر الفرز، يبدأ بتنفيذ مسار حسابي يمر بعدة مراحل دقيقة لضمان النزاهة الهيكلية للمصفوفة. في المرحلة الأولى، يقوم النظام بقراءة وسيطة Header؛ وبما أنها حددت بـ xlYes، يتم عزل الصف 1 بالكامل وحجبه عن خوارزمية التباديل، ليتحول النطاق التنفيذي الفعلي للمعالجة إلى النطاق الفرعي A2:C11.

في المرحلة الثانية، يستهدف المحرك العمود المحدد عبر Key1 (العمود A)، ويطبق عليه خوارزمية فرز سريعة (مثل QuickSort أو خوارزميات الدمج المتطورة المدمجة في نواة إكسيل). تقوم هذه الخوارزمية بمقارنة القيم النصية وإعادة تنظيم الصفوف بأكملها، ناقلة كافة البيانات المرتبطة في العمودين B وC بالتوازي المطلق لضمان عدم حدوث أي انزياح أو انفصال بين اللاعب وناديه ونقاطه.

في المرحلة الثالثة، يتفحص المحرك مخرجات الفرز الأول لرصد مجموعات التماثل (Ties). وحين يكتشف أن نادي “الهلال” يتكرر في عدة صفوف متعاقبة، يقوم بتفعيل المعيار الموجه عبر Key2 (العمود C) بشكل حصري وموضعي داخل تلك المجموعة. فيقوم بترتيب الصفوف المحصورة بين أول ظهور للهلال وآخر ظهور له وفقاً للقيمة العددية للنقاط تنازلياً. وتتسم هذه العملية باستقرار هيكلي فائق، حيث تظل الصفوف المتطابقة تماماً في كلا المفتاحين محتفظة بترتيبها المتبادل الأصلي دون إحداث تشويش في المصفوفة، وكل ذلك في بضعة أجزاء من الألف من الثانية.

6. توسيع خوارزمية الفرز لتشمل ثلاثة أعمدة باستخدام كائن النطاق التقليدي

6.1 دمج المعيار الثالث Key3 وفق المحددات الكلاسيكية

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

لننظر في سيناريو رياضي أو تشغيلي أكثر عمقاً، حيث يشتمل جدولنا على أعمدة: “الفريق” (العمود A)، و”المركز التكتيكي” (العمود B: مثل هجوم، وسط، دفاع)، و”معدل النقاط” (العمود C). في هذا السياق، يمكننا صياغة كود متقدم يطلب من البرنامج فرز الفرق هجائياً أولاً (Key1)، ثم فرز المراكز التكتيكية تصاعدياً لجمع لاعبي الخط الواحد معاً (Key2)، ثم فرز معدل النقاط تنازلياً لترتيب اللاعبين داخل نفس المركز لنفس الفريق وفق كفاءتهم التهديفية (Key3).

تتم صياغة الكود بإدراج الوسائط الإضافية Order3 وKey3 بسلاسة، على النحو التالي:

Range(“A1:C50”).Sort _
    Key1:=Range(“A1”), Order1:=xlAscending, _
    Key2:=Range(“B1”), Order2:=xlAscending, _
    Key3:=Range(“C1”), Order3:=xlDescending, _
    Header:=xlYes

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

6.2 الموازنة التحليلية بين الأولويات عند استخدام معايير ثلاثية

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

في حال حدوث تعادل تام بين سجلين أو أكثر عبر المفاتيح الثلاثة كافة (بأن تطابق الفريق، والمركز، ومعدل النقاط بدقة متناهية)، فإن محرك إكسيل الكلاسيكي يعتمد ما يُعرف بمبدأ “الفرز المستقر” (Stable Sorting)، حيث يترك السجلات المتطابقة تماماً في نفس الترتيب الفيزيائي النسبي الذي كانت عليه قبل تشغيل الماكرو. يمنع هذا السلوك التعديلات العشوائية في مواقع الخلايا ويحافظ على إمكانية تتبع أسبقية الإدخال الأصلي.

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

7. الانتقال إلى كائن SortFields الحديث لفرز أعمدة غير محدودة

7.1 الهندسة البرمجية لكائن Worksheet.Sort الحديث

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

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

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

7.2 خطوات التطبيق العملي لتقنية SortFields

يتطلب تطبيق خوارزمية الفرز الحديثة عبر كائن SortFields اتباع مسار إجرائي منظم وممنهج يتألف من أربع مراحل متتابعة: أولاً، إفراغ المجموعة عبر SortFields.Clear؛ ثانياً، استدعاء التابع SortFields.Add لإضافة كل عمود كمعيار مستقل مع تحديد اتجاهه ونوعه؛ ثالثاً، ضبط الخصائص البيئية العامة للكائن Sort مثل تحديد النطاق الشامل وحالة الترويسة؛ ورابعاً، إطلاق أمر التطبيق النهائي Sort.Apply.

يوضح الكود التالي كيفية فرز أربعة أعمدة متتالية (الفرع، ثم الإدارة، ثم التقييم، ثم تاريخ التعيين) بسلاسة فائقة:

Sub AdvancedMultiColumnSort()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets(“Sheet1”)
    
    With ws.Sort
        .SortFields.Clear
        
        .SortFields.Add Key:=ws.Range(“A2:A100”), _
            SortOn:=xlSortOnValues, Order:=xlAscending
            
        .SortFields.Add Key:=ws.Range(“B2:B100”), _
            SortOn:=xlSortOnValues, Order:=xlAscending
            
        .SortFields.Add Key:=ws.Range(“C2:C100”), _
            SortOn:=xlSortOnValues, Order:=xlDescending
            
        .SortFields.Add Key:=ws.Range(“D2:D100”), _
            SortOn:=xlSortOnValues, Order:=xlAscending
            
        .SetRange ws.Range(“A1:D100”)
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .Apply
    End With
End Sub

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

7.3 الفرز المتقدم بناءً على ألوان الخلايا والخطوط والرموز

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

يتم ضبط هذه الخاصية عبر وسيطة SortOn في التابع SortFields.Add. فعند الرغبة في الفرز حسب لون خلفية الخلية، نمرر الثابت xlSortOnCellColor، مع تحديد كائن اللون المستهدف. وفي حال كان الفرز يستند إلى لون النص المكتوب، نمرر الثابت xlSortOnFontColor، بينما نستخدم xlSortOnIcon للفرز بالاستناد إلى مجموعات أيقونات التنبيه كإشارات المرور الخضراء والصفراء والحمراء.

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

8. ديناميكية تحديد النطاقات: التعامل مع الجداول المتغيرة ذاتياً

8.1 رصد وتحديد آخر صف وآخر عمود برمجياً

يعتبر الاعتماد على نطاقات ثابتة ومكتوبة يدوياً (Hardcoded Ranges) مثل Range(“A1:C100”) في بناء أكواد الفرز خطيئة برمجية كبرى في بيئات العمل الاحترافية. فالبيانات في عالم الواقع تتسم بالديناميكية والتغير المستمر، حيث يتم إضافة صفوف جديدة دورياً أو حذف سجلات قديمة. وإذا تم تطبيق فرز بنطاق ثابت على جدول تمدد إلى الصف 150، فإن الصفوف الخمسين الأخيرة ستسقط بالكامل من الفرز مسببة كارثة في اتساق التقارير.

للتغلب على هذا التحدي الجذري، يلجأ مطورو VBA المحترفون إلى خوارزميات الاستكشاف الديناميكي للحدود الفيزيائية للجداول. ويعد استخدام خاصية End(xlUp) المعيار الذهبي لتحديد آخر صف نشط بدقة بالغة، حيث تحاكي هذه الطريقة ضغط المستخدم على الاختصار (Ctrl + Arrow Up) انطلاقاً من أقصى قاع ورقة العمل وصولاً إلى آخر خلية مأهولة بالبيانات، متفادية أي أخطاء قد تنجم عن وجود خلايا فارغة بين السجلات:

Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, “A”).End(xlUp).Row

بالمثل، يتم حساب آخر عمود نشط أفقياً باستخدام خاصية End(xlToLeft) من أقصى يمين ورقة العمل:

Dim lastCol As Long
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column

عقب الحصول على هذه الإحداثيات الديناميكية، يتم بناء النطاق الإجمالي بدقة متناهية عبر كائن الخلايا: Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol)). يضمن هذا الأسلوب المرن تمدد وانكماش نطاق الفرز تلقائياً مع كل عملية إدخال أو حذف للبيانات، مما يجعل الكود محصناً ضد التقادم وقادراً على العمل المستدام لسنوات طويلة دون أدنى تعديل يدوي.

8.2 استغلال خاصية CurrentRegion للفرز الآلي التلقائي

توفر لغة VBA أداة استكشافية بالغة الذكاء تُعرف بخاصية CurrentRegion، والتي تمثل النظير البرمجي للضغط على الاختصار الشهير (Ctrl + A). وتعرف “المنطقة الحالية” بأنها النطاق المستطيل الكامل المحاط بصفوف وأعمدة فارغة من كافة جوانبه الأربعة، مما يجعلها مثالية لتحديد الجداول المتراصة بمجرد الإشارة إلى أي خلية بداخلها، مثل Range(“A1”).CurrentRegion.

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

ws.Range(“A1”).CurrentRegion.Sort _
    Key1:=ws.Range(“A1”), Order1:=xlAscending, _
    Key2:=ws.Range(“B1”), Order2:=xlDescending, _
    Header:=xlYes

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

8.3 التعامل البرمجي مع جداول إكسيل الرسمية (ListObjects)

مع التحول الحديث في استخدام إكسيل نحو الجداول المنظمة الرسمية المعروفة تقنياً بكائنات ListObject (التي يتم إنشاؤها عبر واجهة المستخدم عبر أمر Format as Table أو Ctrl + T)، تطورت أساليب الفرز لتستفيد من المزايا البنيوية الفائقة لهذه الجداول. يمتلك كائن ListObject محرك فرز مدمج وخاص به يمكن النفاذ إليه مباشرة عبر خاصية ListObject.Sort.

يوفر فرز الجداول الرسمية مزايا استثنائية لا تتوفر في النطاقات التقليدية، لعل أبرزها هو التمدد الذاتي المطلق لنطاق الفرز، والتحديث الفوري لمراجع الأعمدة من خلال أسمائها الهيكلية المعرفة (Structured References) بدلاً من مراجع الحروف والأرقام الجامدة. يوضح الكود التالي كيفية تطبيق فرز مزدوج على جدول رسمي يحمل اسم “SalesTable”:

Sub SortExcelTable()
    Dim tbl As ListObject
    Set tbl = ThisWorkbook.Sheets(“Sheet1”).ListObjects(“SalesTable”)
    
    With tbl.Sort
        .SortFields.Clear
        .SortFields.Add Key:=tbl.ListColumns(“المنطقة”).Range, _
            SortOn:=xlSortOnValues, Order:=xlAscending
        .SortFields.Add Key:=tbl.ListColumns(“المبيعات”).Range, _
            SortOn:=xlSortOnValues, Order:=xlDescending
        .Header = xlYes
        .Apply
    End With
End Sub

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

9. معالجة أنواع البيانات المتباينة والقيم الفارغة وحساسية الأحرف

9.1 فرز التواريخ والبيانات الزمنية إلى جانب القيم الرقمية

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

إذا تم تخزين التواريخ كنصوص، فإن خوارزمية الفرز ستتعامل معها وفقاً للترتيب الهجائي البحت؛ مما يعني أن تاريخاً مثل “01/12/2023” سيسبق تاريخ “02/01/1990″، لأن الحرف الأول “01” يسبق “02” هجائياً، وهو ما ينسف المنطق الزمني للتحليل بالكامل. ولتفادي هذا الخلل، يتعين على المطور دمج إجراءات تطهير مسبقة تقوم بتحويل النصوص إلى قيم تاريخية قياسية عبر الدالة CDate أو استخدام أداة TextToColumns برمجياً لإعادة معايرة التنسيق الزمني داخل العمود قبل إطلاق أمر الفرز.

بالإضافة إلى ذلك، تلعب الإعدادات الإقليمية ومحليات النظام (System Regional Locales) دوراً مؤثراً في تفسير صيغ اليوم والشهر (مثل التمييز بين النسق الأمريكي MM/DD/YYYY والنسق الدولي DD/MM/YYYY). وتضمن البرمجة الواعية تجنب أي لبس زمني عن طريق فرض التنسيق العالمي المتوافق مع معايير ISO (YYYY-MM-DD)، مما يضمن ترتيباً زمنياً تصاعدياً أو تنازلياً دقيقاً وموثوقاً بغض النظر عن بيئة الجهاز التي يعمل عليها التطبيق.

9.2 إدارة الخلايا الفارغة وموضعها في نواتج الفرز

تعتمد خوارزمية الفرز في مايكروسوفت إكسيل، سواء تم تشغيلها يدوياً أو عبر لغة VBA، سلوكاً صارماً وموحداً تجاه الخلايا الفارغة (Blank Cells)؛ حيث يتم دائماً إلقاء الخلايا الفارغة في ذيل وقاع المصفوفة المفرزة، وذلك بصرف النظر تماماً عما إذا كان اتجاه الفرز المعتمد تصاعدياً (xlAscending) أو تنازلياً (xlDescending).

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

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

9.3 التحكم في حساسية حالة الأحرف عبر المعلمة MatchCase

تتيح لغة VBA للمطورين إمكانية التحكم في التمييز بين الحروف الكبيرة والصغيرة (Case Sensitivity) في اللغات اللاتينية كالإنجليزية والفرنسية عبر المعلمة التابعة MatchCase، والتي تقبل إحدى القيمتين المنطقيتين: True أو False. فعند ضبط المعلمة على MatchCase:=True، فإن خوارزمية الترتيب ستتعامل مع النصوص بحساسية تامة لحالة الأحرف، مما يجعل كلمة “apple” تختلف في رتبتها الهجائية عن كلمة “Apple”.

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

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

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

10.1 استراتيجيات تسريع التنفيذ عبر تعطيل تحديث الشاشة والعمليات الثانوية

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

لتحقيق أقصى درجات الكفاءة وتسريع زمن التنفيذ إلى أجزاء من الثانية، يتعين على المطور تطبيق استراتيجية “التثبيط المؤقت للبيئة” في مستهل الكود البرمجي. تتضمن هذه الاستراتيجية إيقاف تحديث الشاشة عبر الخاصية Application.ScreenUpdating = False، وتعطيل الحساب التلقائي للمعادلات عبر تحويله إلى الوضع اليدوي بواسطة Application.Calculation = xlCalculationManual، بالإضافة إلى تجميد معالجة الأحداث التلقائية عبر Application.EnableEvents = False.

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

On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False

‘ تنفيذ عمليات الفرز المتعدد هنا

CleanUp:
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True
    Exit Sub

ErrorHandler:
    MsgBox “حدث خطأ غير متوقع: ” & Err.Description, vbCritical
    Resume CleanUp

10.2 بناء هياكل متينة لاقتناص الأخطاء البرمجية الشائعة

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

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

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

11. أتمتة الفرز التفاعلي: ربط وحدات الماكرو بواجهات المستخدم

11.1 ربط إجراءات الفرز بأزرار التحكم وعناصر النموذج

لا تكتمل المنظومة البرمجية إلا بتوفير قنوات تفاعلية مريحة تتيح للمستخدمين العاديين، الذين يفتقرون إلى الخبرة في فتح محرر الأكواد والتعامل مع الشفرات، تشغيل خوارزميات الفرز المعقدة بنقرة زر واحدة. ويوفر برنامج إكسيل بيئتين أساسيتين لعناصر التحكم: عناصر التحكم في النماذج (Form Controls) وعناصر التحكم ActiveX المتقدمة.

تعد عناصر Form Controls الخيار الأمثل والأنسب لبناء أزرار فرز بديهية ومستقرة؛ إذ يتم رسم الزر مباشرة فوق ورقة العمل وتسميته بعنوان وظيفي واضح (مثل: “فرز حسب المنطقة والمبيعات”)، ثم ربطه عبر النقر بزر الفأرة الأيمن باختيار Assign Macro وتحديد الإجراء المستهدف. وتتميز هذه الأزرار بخفتها وتوافقها التام مع مختلف إصدارات إكسيل وحتى عبر بيئات إكسيل على أنظمة ماك.

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

11.2 تفعيل الفرز التلقائي المستند إلى أحداث ورقة العمل

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

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

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim watchRange As Range
    Set watchRange = Me.Range(“A2:C100”)
    
    If Not Application.Intersect(Target, watchRange) Is Nothing Then
        On Error GoTo ExitHandler
        Application.EnableEvents = False
        
        Me.Range(“A1:C100”).Sort _
            Key1:=Me.Range(“A1”), Order1:=xlAscending, _
            Key2:=Me.Range(“B1”), Order2:=xlDescending, _
            Header:=xlYes
    End If

ExitHandler:
    Application.EnableEvents = True
End Sub

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

12. أفضل الممارسات البرمجية واستكشاف الأخطاء وتصحيحها في VBA

12.1 القواعد الذهبية لكتابة شفرة فرز احترافية وقابلة لإعادة الاستخدام

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

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

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

12.2 دليل استكشاف الأخطاء البرمجية الشائعة وطرق علاجها

يواجه مطورو VBA أثناء تطبيق عمليات الفرز حزمة من الأخطاء المتكررة التي يتطلب علاجها فهماً عميقاً لأسبابها الجذرية. ويأتي في مقدمة هذه المشكلات الخطأ البرمجي الشهير “Runtime error 1004: The sort reference is not valid”، والذي يظهر عادة نتيجة أحد ثلاثة أسباب: إما أن المفتاح المحدد (Key) يقع جغرافياً خارج النطاق المستهدف بالفرز، أو أن مساحة المفتاح لا تتطابق مع المحاذاة الرأسية للأعمدة، أو بسبب محاولة فرز ورقة عمل محمية دون إلغاء حمايتها برمجياً أولاً.

تتمثل المعضلة الكلاسيكية الثانية في عدم اتساق تنسيقات الأرقام المخزنة كنصوص (Numbers Stored as Text)، وهي ظاهرة تتكرر بكثرة عند استيراد البيانات من أنظمة تخطيط الموارد المؤسسية (ERP). يتسبب هذا الخلل في ترتيب رقمي مشوه؛ حيث يسبق الرقم “100” الرقم “20” عند الفرز التصاعدي استناداً للأسبقية الهجائية للرمز “1”. ويكمن الحل البرمجي في تمرير حلقة سريعة تطبق عملية ضرب حسابية في الرقم 1 على النطاق، أو استخدام التابع Range.Value = Range.Value لإجبار محرك إكسيل على إعادة تقييم المحتوى وتخزينه كأرقام حقيقية قبل بدء الفرز.

وأخيراً، يجب الانتباه إلى تأثير الصفوف والأعمدة المخفية (Hidden Rows and Columns) داخل نطاق الفرز؛ فخلافاً لما يعتقده البعض، يفرز محرك إكسيل الصفوف المخفية ويعيد ترتيبها ضمن المصفوفة بشكل طبيعي، ولكنه قد يتسبب في سلوكيات بصرية مفاجئة للمستخدم عند إعادة إظهارها. وتوفر أدوات التنقيح في بيئة VBE، مثل نواة التتبع الفوري (Immediate Window) واستخدام نقاط التوقف (Breakpoints) وشاشات مراقبة المتغيرات (Watch Window)، سبلاً مثالية لتتبع تدفق البيانات لحظة بلحظة وتشخيص أي انحرافات مسارية بدقة متناهية قبل اعتماد الكود النهائي.

خاتمة

تجسد أتمتة عمليات الفرز متعددة الأعمدة عبر لغة Visual Basic for Applications (VBA) إحدى الركائز التحليلية والتقنية الأكثر فاعلية في بيئة مايكروسوفت إكسيل، ناقلة ممارسات إدارة البيانات من حيز المعالجات اليدوية البطيئة والمعرضة للخطأ إلى آفاق الكفاءة المؤسسية والنزاهة الإحصائية الصارمة. وقد كشف هذا الدليل الشامل عن البنية المعمارية المزدوجة التي تتيحها بيئة إكسيل البرمجية، بدءاً من أسلوب Range.Sort الكلاسيكي الذي يتميز بالرشاقة والسرعة الفائقة في معالجة الهرميات الثلاثية البسيطة، وصولاً إلى النموذج المتطور لكائن SortFields التابع لمنظومة Worksheet.Sort، والذي يكسر كافة القيود العددية ويتيح فرزاً غير محدود للأعمدة، مع تمكين المعالجات المتقدمة المستندة إلى السمات البصرية كالألوان والأيقونات الشرطية.

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

المراجع

تقييم هذا المحتوى

0.0 / 5 0 تقييمات

اقتباس هذا المقال

looti, M. (2026, سبتمبر 12). VBA: كيفية فرز ورقة العمل حسب أعمدة متعددة. عرب سايكلوجي. https://arabpsychology.com/statistics/vba-how-to-sort-sheet-by-multiple-columns/
looti, Mohammed. “VBA: كيفية فرز ورقة العمل حسب أعمدة متعددة.” عرب سايكلوجي, 12 سبتمبر 2026, https://arabpsychology.com/statistics/vba-how-to-sort-sheet-by-multiple-columns/.
looti, Mohammed. “VBA: كيفية فرز ورقة العمل حسب أعمدة متعددة.” عرب سايكلوجي. سبتمبر 12, 2026. https://arabpsychology.com/statistics/vba-how-to-sort-sheet-by-multiple-columns/.