محتويات الدورة

SQLite / الأساسي: المحرك المضمّن والبيانات الصحيحة / الدرس 6

التعديل الآمن و RETURNING و UPSERT

عبّر عن انتقال مسموح وتحقق من الصفوف المتأثرة، وميّز التحديث العادي من معالجة تعارض قد تحذف بيانات أو تتجاهلها.

وقت القراءة التقريبي: 5 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • استخدام أعمدة INSERT صريحة و UPDATE يحمي أهلية التغيير.
  • تفسير القيم المتأثرة دون خلطها بتثبيت المعاملة.
  • اختيار UPSERT مع فهم الفرق عن IGNORE و REPLACE.

حدد انتقال الحالة المسموح قبل كتابة التعديل

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

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

عدّل القيمة المخزنة بعملية حسابية محمية

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

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

sql غيّر المخزون بحساب وشرط صريحين
CREATE TABLE stock(id INTEGER PRIMARY KEY,quantity INTEGER NOT NULL CHECK(quantity>=0));
INSERT INTO stock VALUES(1,5);
UPDATE stock SET quantity=quantity-2 WHERE id=1 AND quantity>=2
RETURNING id,quantity;
SELECT changes() AS changed;
الناتج المتوقع
id|quantity
1|3

changed
1

يتغير الصف الوحيد من 5 إلى 3، وتبلغ changes() صفاً واحداً متأثراً بالتحديث. لا تعني هذه المعلومة وحدها دوام معاملة خارجية.

صرح بأعمدة الإدراج ودليل الهوية

اذكر أعمدة INSERT كي لا تعيد إضافة غير مرتبطة للمخطط تفسير القيم الموضعية. قد يحصل المحذوف على افتراضي، وتظل NULL الصريحة مدخلاً آخر تحكمه القيود. يستطيع المحرك اختيار rowid عند حذف INTEGER PRIMARY KEY؛ استرجعه بالمشغل أو RETURNING ولا تخمن التالي من أكبر رقم.

تمثل last_insert_rowid() حالة مرتبطة بالاتصال لا هوية عامة لأي عمل سابق. يعقد تشارك الاتصال والمحفزات افتراضها بسهولة. لا يثبت المعرف المولد تثبيت عملية العمل، ولا تقيس الفجوات عدد السجلات الضائعة بثقة. افصل هوية الطلب وهوية الصف وتأكيد المعاملة عند تصميم النتيجة التي يتلقاها المستدعي.

اختر سياسة تعارض التفرد صراحة

تعالج UPSERT تعارض تفرد بتحديث محدد أو عدم تغيير. يضيف المثال كمية واردة إلى SKU موجود عبر excluded.quantity، أي القيمة المقترحة. ظهرت UPSERT في 3.24.0 وتوسعت صيغها لاحقاً؛ والصيغة هنا مختبرة في 3.45.1. لا تحول كل مخالفة CHECK أو NOT NULL أوعلاقة خارجية إلى مفتاح مكرر.

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

sql اجمع الكمية عند التعارض بسياسة معلنة
CREATE TABLE stock(sku TEXT PRIMARY KEY NOT NULL,quantity INTEGER NOT NULL);
INSERT INTO stock(sku,quantity) VALUES('A',5);
INSERT INTO stock(sku,quantity) VALUES('A',2)
ON CONFLICT(sku) DO UPDATE SET quantity=stock.quantity+excluded.quantity
RETURNING sku,quantity;
الناتج المتوقع
sku|quantity
A|7

تضاف 2 المقترحة إلى 5 الموجودة فتصبح 7 للمفتاح نفسه. هذه سياسة تحديث مقصودة وليست حذفاً وإعادة إدراج للصف.

راجع الحذف واكتمال العملية كلها

تراعي DELETE القيود وقد تشغل حذفاً متسلسلاً. راجع الاحتفاظ والأبناء قبل تصميم الإزالة؛ فالحذف المنطقي أيضاً سياسة تؤثر في الاستعلامات ذات الصلة. لا توفر SQLite صياغة TRUNCATE من محرك آخر كبديل عام. يحتاج الحذف الدفعي اختيار مفاتيح مستقراً وقاعدة تقدم لا افتراض صفوف غير مرتبة.

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

الأخطاء الشائعة وإصلاحها

تغيرت كل الصفوف بدلاً من الهدف المطلوب.

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

حذفت معالجة التكرار بيانات تابعة.

لماذا يحدث؟
عوملت REPLACE على أنها تحديث عادي يحتفظ بالصف.
كيف تصلحه؟
اختر UPSERT أو رفضاً مقصوداً وافحص أثر العلاقة.
كيف تتجنب تكراره؟
اختبر التعارض مع صفوف أبناء موجودة.

زاد المخزون عند تنفيذ بيع.

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

اختبر فهمك

1. لماذا لا تؤمن قراءة مخزون 5 ثم كتابة 1 لطلبين يطلب كل منهما 4؟

اعرض الحل المشروح

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

2. متى تكون DO NOTHING سياسة صحيحة للتكرار؟

اعرض الحل المشروح

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

أهم ما تعلمته

  • يحتاج التعديل هدفاً وأهلية وعقد نتيجة واضحاً.
  • تكشف RETURNING القيم المتأثرة ولا تثبت الدوام وحدها.
  • تختلف آثار UPSERT و IGNORE و REPLACE على البيانات والهوية.

المراجع الرسمية