أدلة هندسية
استيراد CSV في PostgreSQL: القيم الافتراضية وأعمدة الهوية والأعمدة المولّدة
اختر قائمة أعمدة صريحة لـCOPY. افهم القيم المحذوفة من المدخلات، وNULL، وتجاوز قيم الهوية، والتعبيرات المولّدة قبل استيراد بيانات العملاء.
عندما ينبغي أن يوفر PostgreSQL قيمة، احذف ذلك العمود من قائمة مدخلات COPY. لا تضف خلية CSV فارغة بديلًا عن حذف العمود. فقد يتحول الفراغ إلى NULL، ولا تؤدي NULL عادةً إلى تطبيق القيمة الافتراضية للعمود.
هناك قرار ثانٍ: هل يُسمح أصلًا بقيمة من المصدر؟ تتيح القيمة الافتراضية العادية عادةً تجاوزها بقيمة صريحة. أما التعبير المولّد فلا يسمح بذلك. ولأعمدة الهوية قواعدها الخاصة، ومنها استثناء في COPY قد يفاجئ مهندسًا معتادًا على INSERT.
تكتسب هذه الفروق أهمية عندما يحتوي ملف تصدير العميل على حقول مثل id أو created_at أو إجمالي محسوب. قدرة قاعدة البيانات على قبول قيمة وسماح التطبيق بقبولها مسألتان منفصلتان.
النطاق والافتراضات. تستهدف الأمثلة PostgreSQL 17. يدعم PostgreSQL 18 أيضًا الأعمدة المولّدة الافتراضية غير المخزّنة؛ وتستخدم الأمثلة هنا STORED.
صنّف القيم قبل ربط العناوين
| سلوك العمود | ما الذي يوفر القيمة؟ | قرار الاستيراد |
|---|---|---|
| عمود عادي بلا قيمة افتراضية | المصدر أو قيمة موثوقة من التطبيق؛ وإلا فالقيمة NULL | قدّم البيانات المطلوبة صراحةً |
| تعبير DEFAULT عادي | القيمة الافتراضية عند حذف العمود من المدخلات؛ ويمكن لقيمة صريحة أن تحل محلها | حدّد ما إذا كان تجاوز القيمة مسموحًا |
| GENERATED BY DEFAULT AS IDENTITY | المتتالية عند حذف العمود من المدخلات؛ ويمكن تقديم قيم صريحة | اختر سياسة للاحتفاظ بالمعرّفات |
| GENERATED ALWAYS AS IDENTITY | المتتالية في INSERT العادي عند حذف العمود؛ ويتطلب INSERT بقيمة صريحة عبارة تجاوز | لا تفترض أن COPY يرفض المعرّفات المقدمة |
| GENERATED ALWAYS AS (expression) STORED | يحسب PostgreSQL القيمة من الصف | احذفه من قائمة أعمدة COPY |
| مستأجر أو منفّذ عملية يحدده التطبيق | سياق تطبيق مخوّل | استبعده من روابط الحقول التي يتحكم فيها العميل |
وصف القيمة بأنها «تحددها قاعدة البيانات» سياسة استيراد، وليس نوع عمود واحدًا في PostgreSQL. قد يمثل طابع زمني ذو DEFAULT now() حدثًا تاريخيًا يُسمح للمصدر بتقديم قيمته، أو وقت تدقيق يجب ألا يغيّره المصدر أبدًا. لا تحسم أوامر DDL هذا المعنى المتعلق بالعمل.
دوّن القرار لكل حقل على حدة. وللطوابع الزمنية التاريخية، سجّل أيضًا المنطقة الزمنية للمصدر وكيفية التعامل مع القيم الغائبة. وللمعرّفات، وضّح إن كانت مراجع خارجية أم مفاتيح أساسية في بيئة الإنتاج. تطابق الأسماء لا يثبت تطابق الهوية.
استيراد صغير يترك التوليد لـPostgreSQL
نفّذ هذا المثال في جلسة psql واحدة متصلة بقاعدة بيانات PostgreSQL 17 قابلة للتخلص منها. يختفي الجدول المؤقت عند انتهاء الجلسة.
CREATE TEMP TABLE import_lines_demo (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
external_ref text NOT NULL UNIQUE,
quantity integer NOT NULL CHECK (quantity > 0),
unit_price numeric(12,2) NOT NULL CHECK (unit_price >= 0),
status text NOT NULL DEFAULT 'new',
total numeric GENERATED ALWAYS AS (quantity * unit_price) STORED
);
COPY import_lines_demo (external_ref, quantity, unit_price)
FROM STDIN WITH (FORMAT csv, HEADER MATCH);
external_ref,quantity,unit_price
line-a,2,12.50
line-b,3,4.00
\.
SELECT id, external_ref, status, total
FROM import_lines_demo ORDER BY id;تتضمن النتيجة المعرّفين 1 و2، والحالة new في الصفين، والإجماليين 25.00 و12.00. هذا مثال psql يتضمن البيانات داخل الأمر: ينهي السطر المحتوي على شرطة مائلة عكسية تليها نقطة تدفق البيانات. وهو ليس كتلة تُلصق في محرر SQL على الويب.
تحتوي قائمة الاستيراد على ثلاثة أعمدة لأن المصدر يضم ثلاثة حقول. لا تتضمن المدخلات المعرّف والحالة والإجمالي. ويوفرها PostgreSQL وفق تعريف كل منها المختلف. هذا أسهل في المراجعة من إرسال ستة حقول والأمل في أن تحمل القيم الفارغة المعنى الصحيح.
لملف محلي منفصل، استخدم قائمة الأعمدة نفسها مع \copy في psql. يحدد مرجع COPY كيفية تفسير ترتيب الحقول، والأعمدة المحذوفة من المدخلات، وخيارات الإدخال.
الحذف من المدخلات وNULL والفراغ مدخلات مختلفة
في إعدادات CSV الافتراضية في PostgreSQL، يمثل الحقل الفارغ غير المحاط بعلامتي اقتباس القيمة NULL. ويمثل الحقل الفارغ المحاط بعلامتي اقتباس، ""، سلسلة نصية فارغة. ولا يعادل أي منهما حذف عمود من قائمة المدخلات.
external_ref,quantity,unit_price,status
line-c,1,8.00,
line-d,1,8.00,""عند الاستيراد مع تضمين الحالة واستخدام خيارات CSV الافتراضية، يخالف السجل الأول قيد NOT NULL في الجدول. أما الثاني فسيقدم حالة فارغة بدلًا من new. لا يتضمن جدول العرض هذا قيد CHECK للحالات المسموح بها، لذا ستُقبل السلسلة الفارغة وحدها. يوضح ذلك كيف يمكن لما «يقبله PostgreSQL» أن يظل خاطئًا بالنسبة للتطبيق.
في عبارة INSERT، يمكن لكلمة SQL DEFAULT طلب القيمة الافتراضية صراحةً. أما النص DEFAULT في حقل CSV عادي فهو مجرد نص. يوفر PostgreSQL 17 خيارًا منفصلًا لتحديد علامة DEFAULT في COPY؛ فاستخدمه فقط مع اصطلاح ملفات متفق عليه ولا يتعارض مع القيم الفعلية. ولا تحتاج إليه عندما يمكن حذف العمود كله من المدخلات.
عندما تقدم بعض السجلات قيمة عن قصد وتحتاج أخرى إلى القيمة الافتراضية، لا تستطيع قائمة واحدة تحذف العمود التعبير عن الحالتين. تشمل الخيارات علامة موثّقة للقيمة الافتراضية، أو تجميع الصفوف بحسب مجموعة الحقول المكتوبة، أو التجهيز الوسيط ثم عبارات INSERT مدروسة. لا تستبدل هذا التمييز بقاعدة «الفارغ يعني القيمة الافتراضية» إلا إذا اعتمد مالك البيانات هذه القاعدة فعلًا.
يمكن لـCOPY تقديم قيمة لعمود هوية ALWAYS
يمنع GENERATED ALWAYS AS IDENTITY عبارة INSERT العادية من تقديم قيمة الهوية دون إجراء خاص. ومع ذلك، يستطيع COPY FROM استخدام المعرّفات الموجودة في مدخلاته. تعامل مع ذلك بوصفه قدرة صريحة للاستيراد، لا حدًا لفرض التخويل.
بعد العرض السابق، يمكن لأمر COPY التالي إدراج معرّف مختار:
COPY import_lines_demo (id, external_ref, quantity, unit_price)
FROM STDIN WITH (FORMAT csv);
900,line-explicit,1,1.00
\.إذا كانت سياستك إنشاء هويات جديدة في الوجهة، فاستبعد id من خريطة الربط وقائمة COPY معًا. وإذا كان الاحتفاظ بالمعرّفات مقصودًا، فتحقق من التعارضات وحالة المتتالية المرتبطة. تقديم قيمة هوية لا يرفع بحد ذاته قيمة المتتالية إلى أكبر معرّف مستورد؛ وقد تتعارض معها لاحقًا قيمة مولّدة.
إصلاح المتتالية جزء من خطة الترحيل التي يضعها مالك قاعدة البيانات. لا تنفّذ أمرًا عامًا من نوع «اضبط المتتالية على أكبر معرّف» أثناء عمليات كتابة متزامنة من التطبيق: فقد تكون بعض القيم قد خُصصت بالفعل. اختبر الإجراء المختار مسبقًا في ظل ظروف التزامن والصيانة الخاصة بالتطبيق. يشرح توثيق أعمدة الهوية ومرجع دوال المتتاليات هذه الآليات.
يُعاد حساب التعبيرات المولّدة ولا تُستورد قيمها
قد يحتوي جدول العميل على عمود «إجمالي» خاص به. في جدول المثال، يُحسب إجمالي الوجهة من الكمية وسعر الوحدة. أبقِ إجمالي المصدر خارج خريطة الكتابة، وقارنه بصورة منفصلة إن كان دليلًا مفيدًا.
إذا اختلف الإجماليان، فحدّد أي قاعدة منهما خاطئة. قد يحسب نظام المصدر الضريبة قبل التقريب، بينما يقرّب النظام المستهدف أولًا. استبدال قيمة مولّدة في الوجهة ليس مسار التصحيح. تحتاج إما إلى تحويل معتمد للمدخلات، أو إلى تغيير خاضع للمراجعة في نموذج الوجهة.
يدعم PostgreSQL 17 الأعمدة المولّدة المخزّنة. يجري التوليد بعد تغييرات مشغلات BEFORE ذات الصلة على الصف الأساسي. لذلك فإن وجود تعبير مولّد لا يثبت أن القيمة ستساوي حسابًا أُجري سابقًا في المعاينة. اقرأ التعبير والمشغلات المنطبقة، ثم اختبر مسار الكتابة الفعلي. راجع قواعد الأعمدة المولّدة في PostgreSQL 17.
ما الذي ينبغي تضمينه في مراجعة الاستيراد
سجّل لكل عمود الجهة التي توفر قيمته، وقاعدة حذفه من المدخلات، وقيم المصدر المسموح لها بتجاوز قيمته، والأدلة التي يستند إليها القرار. ضمّن الجدول المستهدف المحدد وقائمة أعمدة COPY المرتبة. وإذا كانت قيمة مطلوبة تأتي من التطبيق، فسمِّ الجهة المخوّلة التي توفرها.
- اختبر حذف القيمة من المدخلات، وNULL، والقيمة الفارغة كلًا على حدة حيث يكون لذلك معنى.
- اختبر محاولة تجاوز المصدر لقيمة كل عمود محمي.
- تحقق مما إذا كان الاحتفاظ بالمعرّفات يتطلب إجراءً للمتتالية أو لربط المراجع.
- قارن القيم المشتقة المخزّنة بقواعد العمل المعتمدة بعد الإدراج.
يمكن لـPG Import Check المساعدة في تصنيف DDL المقدّم: إذ تبقى قيم المصدر المطلوبة، والقيم الافتراضية العادية، وأعمدة الهوية، والتعبيرات المولّدة فئات متميزة. وتعرض الأداة أيضًا النتائج البنيوية وفجوات التحليل. وهي لا تنفذ التعبيرات، ولا تفحص المخطط الفعلي، ولا تتحقق من سجلات المصدر، ولا تستنتج أن وجود قيمة افتراضية يمنح صلاحية تقديم قيمة للحقل.
لحقول مثل معرّف المستأجر، تابع إلى دليل الصلاحيات وRLS. وللتحقق من القيم الناتجة، استخدم التحقق بعد الاستيراد.