أدلة هندسية
كيفية التحقق من استيراد CSV في PostgreSQL
افحص ما يتجاوز عدد الصفوف بعد استيراد بيانات عميل. قارن المفاتيح المقبولة، والقيم المحوّلة، ونطاق المستأجر، والنتائج غير المحسومة باستخدام SQL في PostgreSQL.
قارن سجلات المصدر المقبولة بسجلات الوجهة المثبتة باستخدام مفاتيح ثابتة، ثم تحقق من القيم المهمة والثوابت التي يجب أن تحافظ عليها قواعد العمل. افصل الاستبعادات، وعمليات الكتابة الفاشلة، والنتائج غير المحسومة. تطابق الأعداد فحص أولي مفيد، لكنه لا يوضح ما إذا كانت السجلات الصحيحة قد وصلت.
يمكن اختصار الفكرة هكذا: الإدراج يثبت حدوث الإدراج؛ ومطابقة النتائج تثبت صحتها. الجزء الثاني مشروط: لا تثبت مطابقة النتائج الصحة إلا وفق المقارنات والثوابت التي اخترتها فعلًا. ولا يمكنها إثبات قاعدة عمل لم تُذكر.
تكشف الأمثلة أدناه عن استيراد خاطئ يجتاز فحص عدد الصفوف، ثم توضح كيفية اكتشافه.
النطاق والافتراضات. PostgreSQL 17. توضح جداول مؤقتة ببيانات اصطناعية مطابقة نتائج مجموعة مقبولة واحدة محصورة بنطاق مستأجر؛ ولا تتصل هذه الجداول ببيانات العملاء.
التحقق من الصلاحية والإدراج ومطابقة النتائج تجيب عن أسئلة مختلفة
| المرحلة | السؤال | حدود الفحص |
|---|---|---|
| التحقق المسبق من الصلاحية | هل تستوفي هذه البيانات المقترحة القواعد التي فحصناها؟ | قد لا يرى الحالة الفعلية، أو التغييرات المتزامنة، أو السلوك الفعلي للمشغلات |
| أدلة الإدراج / التثبيت | هل ثُبّتت عمليات الكتابة هذه في قاعدة البيانات؟ | لا تثبت هوية المصدر أو المعنى في مجال العمل |
| مطابقة النتائج | هل تتفق النتيجة المرصودة مع المصدر المقبول والثوابت المختارة؟ | لا تغطي إلا النطاق واللقطة والمقارنات التي شملها الفحص |
حافظ على وضوح هذه الفروق في الواجهة وعند التسليم. «جرى تحليل CSV» لا تعني «اجتاز الاستيراد التحقق من الصلاحية». و«استلمه الخادم» لا تعني «ثبّتته قاعدة البيانات». و«أُدرج 200 سجل» لا تعني «كل بيانات العميل صحيحة».
يأتي دور أداة فحص DDL قبل هذه الفحوص للنتائج الفعلية. يمكن لـPG Import Check إظهار المتطلبات المعلنة وفجوات التحليل في SQL المقدّم. وهي لا تتحقق من سجلات CSV، ولا تستعلم عن الوجهة، ولا تطابق النتائج.
ثبّت ما تتوقع العثور عليه
قبل التنفيذ، احتفظ بمجموعة مقبولة خضعت للمراجعة. ينبغي أن تحدد سجلات المصدر التي ستُكتب، وقيمها المحوّلة المعتمدة، والمستأجر، ونطاق أسماء النظام المصدر المعني. احتفظ معها بخريطة الربط وإصدار القواعد.
سجّل الاستبعادات صراحةً. إذا احتوى ملف من 205 سجلات على خمس جهات اتصال مستبعدة عن قصد، فمجموعة الإدراج المتوقعة هي 200. وإذا فُقدت تلك السجلات الخمسة لأن عملية ربط لم تجد سجلًا أصليًا، فهي خسائر غير مفسّرة إلى أن يعتمد شخص كيفية التعامل معها.
اختر مفتاحًا ثابتًا. قد يكون مرجع جهة اتصال خارجيًا محصورًا بنطاق المستأجر، أو خريطة معرّفات مولّدة في الوجهة، أو سجل استيراد يربط سجلات المصدر بهويات الوجهة. عنوان البريد الإلكتروني ليس تلقائيًا مفتاحًا مناسبًا: فقد يتغير، أو يكون مشتركًا، أو يغيب.
إذا كانت الوجهة تفتقر إلى هوية ثابتة للمطابقة أو بيانات موثوقة تنسب الصفوف إلى عملية الاستيراد، فأقرّ بهذا القيد قبل الكتابة. قد تشمل نافذة زمنية أو فروق الأعداد نشاطًا متزامنًا في التطبيق. أضف طريقة خاضعة للمراجعة لتحديد صفوف هذا الاستيراد، أو ضيّق نطاق ما تدّعي أن التحقق يثبته.
عرض توضيحي: أعداد متساوية وسجلات مختلفة
نفّذ هذا الإعداد في جلسة PostgreSQL 17 قابلة للتخلص منها. يمثل الجدولان المستأجر محل المراجعة فقط؛ وتفرض مفاتيحهما الأساسية التفرد داخل هذا المثال.
CREATE TEMP TABLE import_expected_demo (
tenant_id integer NOT NULL,
external_ref text NOT NULL,
display_name text,
PRIMARY KEY (tenant_id, external_ref)
);
CREATE TEMP TABLE import_actual_demo (
tenant_id integer NOT NULL,
external_ref text NOT NULL,
display_name text,
PRIMARY KEY (tenant_id, external_ref)
);
INSERT INTO import_expected_demo VALUES
(10, 'contact-a', 'Ada'),
(10, 'contact-b', 'Bela'),
(10, 'contact-c', NULL);
INSERT INTO import_actual_demo VALUES
(10, 'contact-a', 'Ada'),
(10, 'contact-c', ''),
(10, 'contact-d', 'Dara');
SELECT
(SELECT count(*) FROM import_expected_demo WHERE tenant_id = 10)
AS expected_count,
(SELECT count(*) FROM import_actual_demo WHERE tenant_id = 10)
AS actual_count;العددان كلاهما ثلاثة. ومع ذلك، فإن جهة الاتصال B مفقودة، وجهة الاتصال D غير متوقعة، وجهة الاتصال C لها اسم فارغ بدلًا من NULL. لهذا فإن تساوي الأعداد ضروري لهذا التوقع المحدد الذي يقابل كل سجل بسجل واحد، لكنه غير كافٍ لإثبات الصحة.
قارن وجود العناصر في المجموعتين في الاتجاهين
استخدم مفاتيح العمل المقبولة للعثور على السجلات المفقودة:
SELECT external_ref
FROM import_expected_demo WHERE tenant_id = 10
EXCEPT
SELECT external_ref
FROM import_actual_demo WHERE tenant_id = 10;يعيد هذا الاستعلام contact-b. اعكس المقارنة للعثور على السجلات غير المتوقعة:
SELECT external_ref
FROM import_actual_demo WHERE tenant_id = 10
EXCEPT
SELECT external_ref
FROM import_expected_demo WHERE tenant_id = 10;يعيد هذا الاستعلام contact-d. في جدول إنتاج يحتوي على جهات اتصال موجودة مسبقًا، لا تقارن المستأجر بأكمله بمجموعة مقبولة لاستيراد جديد ثم تصف كل جهة اتصال قديمة بأنها غير متوقعة. حدّد نطاق الصفوف الفعلية باستخدام بيانات موثوقة تنسبها إلى الاستيراد، أو قارنها بتوقع كامل بُني صراحةً لحالة البيانات بعد الاستيراد.
يزيل EXCEPT الصفوف المكررة من الناتج. تضمن المفاتيح الأساسية هنا التفرد. ودون ذلك الضمان، قد يخفي تساوي المجموعات أخطاء في عدد مرات تكرار العناصر. افحص أعداد السجلات مجمّعة بحسب المفتاح، أو استخدم مقارنة مناسبة للمجموعات متعددة العناصر مثل EXCEPT ALL، مع فهم دلالات NULL وتوحيد القيم.
قارن القيم بدلالات تتعامل مع NULL على نحو صحيح
بعد حسم وجود عناصر المجموعتين، قارن الحقول المهمة. استخدم التمثيل المتوقع بعد التحويل بدلًا من سلسلة خام وُحّدت عن قصد.
SELECT expected.external_ref,
expected.display_name AS expected_name,
actual.display_name AS actual_name
FROM import_expected_demo AS expected
JOIN import_actual_demo AS actual
ON actual.tenant_id = expected.tenant_id
AND actual.external_ref = expected.external_ref
WHERE expected.tenant_id = 10
AND expected.display_name IS DISTINCT FROM actual.display_name;يعيد هذا الاستعلام جهة الاتصال C. تنتج مقارنة <> عادية تتضمن NULL قيمة غير معروفة، ولذلك قد تفوّت عدم التطابق داخل عبارة WHERE. يوفر IS DISTINCT FROM المقارنة التي تراعي NULL والمستخدمة هنا. يتعامل الربط عمدًا مع المفاتيح المتطابقة؛ ولا يحل محل فحوص المفاتيح المفقودة.
اختر ثوابت مجال العمل مع مالك البيانات. في استيراد جهات الاتصال، قد يعني ذلك المستأجر المعتمد وعلاقة الشركة، وحالات دورة الحياة المسموح بها، والحفاظ على المراجع الخارجية. وفي استيراد الفواتير، قد يعني الإجماليات بحسب العملة وحالة المستند. قد يخفي مجموع عام واحد أخطاء يلغي بعضها أثر بعض.
قارن القيم التي تولدها قاعدة البيانات وفق خصائصها المقصودة. لا تتوقع أن يساوي معرّف مولّد حديثًا معرّفًا قديمًا. ولإجمالي محسوب، اختبر الحساب والتقريب المتفق عليهما. ولطابع زمني للتدقيق، اختبر القاعدة الزمنية الموثّقة. راجع القيم المولّدة والقيم الافتراضية.
حدّد مصير كل سجل مصدر مرة واحدة
حدّد حالات لا تتداخل فيما بينها لتدفق عملك. في استيراد يقتصر على الإدراج، يفصل الحصر النهائي المفيد بين الاستبعادات المعتمدة، والسجلات المؤكد تثبيتها، والسجلات المؤكد عدم إدراجها، والسجلات غير المحسومة. يندرج العمل الذي لم تُجرَ محاولته ضمن فئة غير المُدرج مع سبب مستقل؛ ولا توحِ بأنه فشل في فحص بقاعدة البيانات.
205 parsed source records
5 approved exclusions
196 confirmed committed
2 confirmed non-inserted (rejected batch)
2 unresolved (commit evidence unavailable)
---
205 accounted for; import is not yet completeهذا مثال لاصطلاح حصر النتائج، وليس مخططًا عامًا لكل الحالات. يحتاج تدفق upsert أيضًا إلى التمييز بين السجلات المدرجة، والمحدّثة، والتي تُركت دون تغيير عن قصد. وقد يحتوي مصدر أُزيلت تكراراته على عدة سجلات مصدر تمثل كيانًا مقبولًا واحدًا؛ فسجّل هذه العلاقة بدلًا من فرض معادلة غير صالحة تقابل كل صف بصف واحد.
انتهاء مهلة الشبكة لا يثبت عدم حدوث أي كتابة. ارجع إلى إيصال محفوظ بشكل دائم أو دليل من قاعدة البيانات يحدد المحاولة. وإذا بقيت النتيجة مجهولة، فأبقِها كذلك وأوقف إعادة محاولة كل شيء بلا تحقق. يشرح دليل تصميم أداة الاستيراد نمطًا ذريًا للكتابة وتسجيل الإيصال معًا.
استخدم لقطة متسقة، ثم اختبر التطبيق
قد تصف عدة استعلامات تُنفّذ في أوقات مختلفة حالات مختلفة لقاعدة البيانات. لتطبيق يعمل فعليًا، حدّد ما إذا كان التحقق يستخدم نافذة كتابة مضبوطة، أو لقطة متسقة لقاعدة البيانات، أو عرضًا ثابتًا خاصًا بالاستيراد. اختبر تكلفة هذا الاختيار مسبقًا؛ فالمعاملة الطويلة لها آثار تشغيلية.
في مستوى العزل الافتراضي Read Committed في PostgreSQL، قد ترى العبارات المنفصلة لقطات مختلفة للبيانات المثبتة. يوفر Repeatable Read لقطة متسقة للمعاملة، لكنه لا يجمّد واقع العمل ولا يشمل المعاملات التي تُثبّت بعد تلك اللقطة. راجع توثيق العزل.
بعد مقارنات قاعدة البيانات، اختبر التطبيق بالمستخدم المقصود. فقد يكون الصف موجودًا لكن RLS يخفيه، أو يكون مرتبطًا بمستأجر آخر، أو مستبعدًا بمرشّح للحالة، أو فاقدًا لعلاقة مطلوبة. راجع أيضًا الآثار اللاحقة: فقد يحتاج إرسال بريد إلكتروني أو استدعاء API خارجي إلى دليل مستقل يتجاوز الصف المُدرج.
قد تساعد العينات في اكتشاف مشكلات التنسيق أو تجربة المستخدم؛ لكنها لا تثبت تطابق جميع الصفوف. وضّح الفحوص التي غطت المجموعة المقبولة كاملة، وتلك التي اقتصرت على عينات.
اجعل سجل القبول مفيدًا لاحقًا
احتفظ بسجل تسليم مختصر يتضمن هوية المصدر المقبول، وإصدار خريطة الربط والقواعد، والوجهة والمستأجر، وأدلة التنفيذ، والاستبعادات، ونتائج المقارنة، والفحوص غير المحسومة. ضمّن اسم من راجع المعنى المتعلق بالعمل، ووقت إجراء التحقق.
لا تضع سجلات العملاء الخام في السجلات الاعتيادية أو التذاكر العامة. احتفظ ببيانات التشخيص فقط حيث يكون ذلك مخوّلًا، وقيّد الوصول إليها، واتفق على حذفها. قد يكون المرجع الخارجي نفسه حساسًا حتى إن لم يكن اسمًا أو عنوان بريد إلكتروني.
إذا فشل فحص، فتحرَّ السبب قبل تغيير بيئة الإنتاج. تصحيح قيمة مصدر، وإصلاح خريطة ربط، والتعويض عن عملية كتابة مثبتة إجراءات مختلفة. احتفظ بدليل النتيجة الأصلية حتى لا يمحو الإصلاح ما يحتاج إلى تفسير.