التصدير مهمّة الـ shell، ليس جملة SQL
مفيش في SQLite حاجة زي COPY ... TO أو SELECT INTO OUTFILE التي بتلاقيها في Postgres أو MySQL. عملية تصدير بيانات SQLite بتتم من خلال الـ shell بتاع sqlite3 نفسه، عن طريق أوامر النقطة (dot-commands): .mode و.headers و.output و.dump. بمجرد ما تتقن الأربعة دول، تقدر تطلّع CSV أو JSON أو نص عادي أو حتى dump كامل لقاعدة البيانات.
الفكرة ببساطة: إنت بتقول للـ shell إزاي يهيّئ النتائج عن طريق .mode، و_هل_ يضمّن أسماء الأعمدة عن طريق .headers، و_فين_ يبعت الناتج عن طريق .output. بعد كده بتشغّل الاستعلام، وتلاقي نتيجته راحت للملف على طول.
تعالى نجهّز قاعدة بيانات صغيرة نلعب بيها:
ثلاثة صفوف وأربعة أعمدة. سنقوم بتصدير هذه البيانات بعدة صيغ مختلفة.
تصدير جدول sqlite إلى csv باستخدام .mode csv مع العناوين
صيغة CSV هي الأكثر شيوعًا لتصدير بيانات sqlite — فجداول البيانات وأنابيب معالجة البيانات ومعظم الأدوات الأخرى تتعامل معها بسلاسة. من داخل صدفة sqlite3:
sqlite> .mode csv
sqlite> .headers on
sqlite> .output users.csv
sqlite> SELECT * FROM users;
sqlite> .output stdout
ما الذي حدث للتو:
.mode csvيُنسّق كل صف على شكل قيم مفصولة بفواصل، مع إحاطة الحقول التي تحتوي على فواصل أو علامات اقتباس أو أسطر جديدة بعلامات اقتباس..headers onيُضيف صفًا أولًا يحتوي على أسماء الأعمدة. بدونه، يخرج ملف CSV بلا ترويسة — وهذا غالبًا ليس ما تريده..output users.csvيُحوّل النتائج إلى ملف. من هذه اللحظة، تذهب مخرجات الاستعلامات إلى الملف بدلًا من الشاشة.- يُنفَّذ استعلام
SELECTويكتب نتائجه إلى الملف بصمت. .output stdoutيُعيد توجيه المخرجات إلى الطرفية مجددًا حتى ترى نتائج الاستعلام التالي.
الملف الناتج:
id,name,email,signup_date
1,"Ada Lovelace",ada@example.com,2025-01-15
2,"Boris Johnson",boris@example.com,2025-02-03
3,"Carmen Diaz",carmen@example.com,2025-03-22
يمكنك تصدير نتائج أي استعلام، وليس الجداول كاملةً فحسب — اعمل فلترة أو join أو تجميعًا، ثم وجِّه المخرجات إلى ملف:
sqlite> .output recent_users.csv
sqlite> SELECT name, email FROM users WHERE signup_date >= '2025-02-01';
sqlite> .output stdout
تصدير بيانات sqlite بأمر واحد من الـ Shell
ما تحتاج تفتح الـ shell التفاعلي أصلًا. تقدر تمرّر أوامر النقطة (dot-commands) وأوامر SQL مباشرة إلى sqlite3 من سطر أوامر نظام التشغيل:
sqlite3 mydb.sqlite <<EOF
.headers on
.mode csv
.output users.csv
SELECT * FROM users;
EOF
هذه هي الصيغة المناسبة للسكربتات ومهام cron — قابلة للتكرار، وبدون أي كتابة يدوية. الأمر .output يبقى محصورًا داخل الجلسة الحالية، فلا يُسرّب أي حالة إلى الخارج.
تصدير sqlite إلى JSON باستخدام .mode json
عندما تريد تصدير البيانات إلى تطبيق ويب أو أداة تتعامل مع JSON، يقوم .mode json بإخراج مصفوفة من الكائنات، كائن واحد لكل صف:
sqlite> .mode json
sqlite> .output users.json
sqlite> SELECT * FROM users;
sqlite> .output stdout
الملف:
[{"id":1,"name":"Ada Lovelace","email":"ada@example.com","signup_date":"2025-01-15"},
{"id":2,"name":"Boris Johnson","email":"boris@example.com","signup_date":"2025-02-03"},
{"id":3,"name":"Carmen Diaz","email":"carmen@example.com","signup_date":"2025-03-22"}]
الترويسات هنا مدمجة ضمن JSON نفسه (المفاتيح)، لذلك لا يكون لأمر .headers أي تأثير. وإذا أردت تنسيقًا مخصصًا — كالكائنات المتداخلة أو إعادة تسمية الحقول — فيمكنك تشكيله مباشرةً داخل الاستعلام باستخدام json_object():
وبهذا تحصل على سلسلة JSON لكل صف مع تحكّم كامل في البنية. ادمجها مع json_group_array() لتجميع النتيجة كاملةً في مستند JSON واحد.
التفريغ الكامل لـ SQL: الأمر .dump
يختلف .dump اختلافًا جوهريًا عن تصدير CSV أو JSON، إذ يُنتج ملف .sql يحتوي على البنية (schema) والبيانات معًا على هيئة عبارات CREATE TABLE وINSERT — أي ما يكفي لإعادة بناء قاعدة البيانات من الصفر:
sqlite3 mydb.sqlite .dump > backup.sql
A snippet of what comes out:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
signup_date TEXT NOT NULL
);
INSERT INTO users VALUES(1,'Ada Lovelace','ada@example.com','2025-01-15');
INSERT INTO users VALUES(2,'Boris Johnson','boris@example.com','2025-02-03');
INSERT INTO users VALUES(3,'Carmen Diaz','carmen@example.com','2025-03-22');
COMMIT;
الاستعادة هي العملية المعاكسة تمامًا، إذ يكفي تمرير الملف إلى قاعدة بيانات جديدة:
sqlite3 restored.sqlite < backup.sql
.dump هو الأداة المناسبة لأخذ النسخ الاحتياطية، وحفظ لقطات (snapshots) من بيانات الاختبار في نظام التحكم بالإصدارات، ونقل قاعدة البيانات بين الأجهزة. فهو يحافظ على كل شيء في المخطط: الفهارس، والمشغّلات (triggers)، والـ views.
تصدير جدول واحد باستخدام dump
يقبل أمر .dump اسم جدول معيّن (أو نمطًا) لحصر المخرجات عليه:
sqlite3 mydb.sqlite ".dump users" > users_only.sql
هذا الأمر يُصدِّر فقط مخطط جدول users مع صفوفه. مفيد لما تبغى تنقل جدولاً واحداً إلى قاعدة بيانات أخرى دون باقي الجداول. كذلك يدعم مطابقة الأنماط: الأمر .dump 'log_%' يُصدِّر كل جدول يبدأ اسمه بـ log_.
تصدير المخطط فقط دون البيانات
أحياناً تحتاج البنية وحدها بدون الصفوف — سواء لأغراض التوثيق، أو لتجهيز بيئة تطوير نظيفة، أو لمقارنة المخططات بين عدة قواعد بيانات. الأمر .schema يطبع جُمل CREATE لا غير:
sqlite3 mydb.sqlite .schema > schema.sql
اقرنه باسم الجدول للحصول على جدول واحد فقط:
sqlite3 mydb.sqlite ".schema users" > users_schema.sql
المخرجات هنا عبارة عن SQL خام — CREATE TABLE وCREATE INDEX وCREATE TRIGGER — جاهزة للتنفيذ مباشرةً على قاعدة بيانات فارغة.
أوضاع أخرى مفيدة في .mode
الأمر .mode لا يقتصر على CSV وJSON فحسب، بل يوفّر خيارات أخرى تستحق المعرفة:
.mode column -- أعمدة محاذاة، مناسبة للقراءة في الطرفية
.mode markdown -- جداول مفصولة بالشرطة العمودية، متوافقة مع GitHub
.mode html -- إخراج جدول HTML <table>
.mode tabs -- قيم مفصولة بعلامات التبويب (TSV)
.mode insert users -- يُصدر عبارات INSERT للجدول المحدد
.mode quote -- قيم مقتبسة بصيغة SQL، مفيدة للفحص
.mode markdown مفيد جدًا لما تبغى تلصق نتائج استعلام داخل ملف README أو في وصف Pull Request. أما .mode insert <table> فهو طريقة سريعة لتوليد بيانات أولية (seed data) — نفّذ استعلام SELECT، التقط عبارات INSERT الناتجة، ثم الصقها في ملف الـ fixtures.
sqlite> .mode insert users
sqlite> .output seed.sql
sqlite> SELECT * FROM users WHERE signup_date >= '2025-02-01';
sqlite> .output stdout
ملاحظات عملية مهمة
.output stdout(أو.outputبدون أي وسيط) يعيد الإخراج إلى الطرفية. لو نسيت هذه الخطوة، ستُكتب نتائج الاستعلام التالي بصمت داخل الملف وتختفي عن نظرك.- تصدير CSV لا يحفظ أنواع البيانات. كل القيم تتحول إلى نص داخل الملف، ولإعادة استيرادها تحتاج إلى مخطط (schema) جاهز يفسّر هذه القيم. لو كنت تنوي نقل البيانات بين قواعد SQLite مع الحفاظ على بنيتها، استخدم
.dumpبدلاً من ذلك. - التصديرات الكبيرة تُكتب بأسلوب متدفّق (streaming). فالأمر
.outputيكتب كل صف فور إنتاجه، ما يعني أنك تستطيع تصدير جداول أكبر من حجم الذاكرة دون أي مشاكل. - للنسخ الاحتياطي الحي لقاعدة بيانات قيد التشغيل، يؤدي
.dumpالمهمة، لكن الأمر المخصّص.backup(سنتناوله لاحقًا في المنهج) أسرع وأكثر أمانًا لأنه يعتمد على واجهة النسخ الاحتياطي المباشر (Online Backup API) في SQLite.
ما التالي: قراءة البيانات
أصبحت الآن تملك صورة كاملة عن كتابة البيانات: INSERT وUPDATE وDELETE وUPSERT وRETURNING، إضافة إلى الاستيراد من CSV والتصدير إليه. يبقى النصف الآخر من العمل مع قواعد البيانات: قراءة البيانات بكفاءة. جملة SELECT هي ما ستقضي معظم وقتك في كتابته، وهي موضوع الصفحة التالية.
الأسئلة الشائعة
كيف أصدّر جدولاً في SQLite إلى ملف CSV؟
من داخل صدفة sqlite3، فعّل وضع CSV، وشغّل العناوين، ثم وجّه المخرجات إلى ملف ونفّذ الاستعلام: .mode csv ثم .headers on ثم .output users.csv ثم SELECT * FROM users;. وبعد الانتهاء نفّذ .output stdout لإعادة المخرجات إلى الطرفية.
ما الفرق بين .dump والتصدير إلى CSV؟
الأمر .dump ينتج ملف .sql يحتوي على جمل CREATE TABLE وINSERT — أي كل ما تحتاجه لإعادة بناء قاعدة البيانات من الصفر. أما CSV فيصدّر صفوف استعلام واحد أو جدول واحد فقط، بدون مخطط (schema). استخدم .dump للنسخ الاحتياطي والترحيل، واستخدم CSV عندما تريد تمرير البيانات إلى Excel أو أدوات أخرى.
هل يمكنني تصدير نتائج استعلام SQLite إلى JSON؟
نعم. إما أن تضبط .mode json داخل الصدفة وتنفّذ أي SELECT، أو تستخدم الدوال المدمجة json_object() وjson_group_array() لبناء JSON داخل الاستعلام نفسه. الطريقة الأولى أسهل للتصديرات السريعة، بينما توفّر الدوال تحكماً كاملاً في شكل المخرجات.