قواعد البيانات: منشئ الاستعلامات
مقدمة
يوفّر منشئ استعلامات قاعدة بيانات Laravel واجهة ملائمة وسلسة لإنشاء وإدارة استعلامات قاعدة البيانات. يمكن استخدامه لتنفيذ معظم عمليات قاعدة البيانات بتطبيقك كما أنه يعمل على جميع أنظمة قواعد البيانات المدعومة.
يستخدم منشئ استعلامات Laravel ارتباط المعاملة PDO لحماية تطبيقك من هجمات حقن SQL. لا حاجة لتنظيف السلاسل النصيّة التي تُمرّر كارتباطات.
استرداد النتائج
استرداد جميع الصفوف من الجدول
تستطيع استخدام التابع table
على الواجهة الساكنة DB
لبدء استعلام. يرد التابع table
نسخة منشئ استعلامات فصيحة (fluent) للجدول المحدد، ممّا يسمح لك بربط المزيد من القيود بالاستعلام ثم الحصول على النتائج في النهاية باستخدام التابع get
:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* عرض قائمة كل مستخدمي التطبيق.
*
* @return Response
*/
public function index()
{
$users = DB::table('users')->get();
return view('user.index', ['users' => $users]);
}
}
يعيد التابع get
الملف Illuminate\Support\Collection
الذي يحتوي على النتائج بحيث تكون كل نتيجة نسخة من الكائن PHP StdClass
. تستطيع الوصول لقيمة كل عمود عن طريق الوصول للعمود كخاصية للكائن:
foreach ($users as $user) {
echo $user->name;
}
استرداد صف أو عمود مفرد من جدول
تستطيع استخدام التابع first
إن احتجت لاسترداد صف واحد فقط من جدول قاعدة البيانات. سيعيد هذا التابع كائن StdClass
واحد:
$user = DB::table('users')->where('name', 'John')->first();
echo $user->name;
تستطيع استخراج قيمة واحدة من سجلّ ما باستخدام التابع value
إن لم تحتج حتى لصفّ كامل. سيعيد هذا التابع قيمة العمود مباشرة:
$email = DB::table('users')->where('name', 'John')->value('email');
استرداد قائمة قيم الأعمدة
تستطيع استخدام التابع pluck
إن رغبت في استرداد مجموعة تحتوي على قيم عمود واحد. سنسترد في هذا المثال، مجموعة من عناوين الوظائف (roles):
$titles = DB::table('roles')->pluck('title');
foreach ($titles as $title) {
echo $title;
}
تستطيع أيضًا تحديد عمود مفاتيح مخصصّة للمجموعة المردودة:
$roles = DB::table('roles')->pluck('title', 'name');
foreach ($roles as $name => $title) {
echo $title;
}
تقسيم النتائج (Chunking Results)
من المُقترح استخدام التابع chunk
إن إحتجت للعمل مع الآلاف من سجلات قاعدة البيانات. يعيد هذا التابع جزءًا صغيرًا من النتائج كل مرّة ويعطي كل قطعة لنطاق مغلق Closure للمعالجة. هذا التابع مفيد جدًا في كتابة الأوامر Artisan التي تعالج آلاف السجلات. دعنا نعمل مثلًا مع الجدول users كاملًا لكن على أجزاء من 100 سجل في كل مرّة:
DB::table('users')->orderBy('id')->chunk(100, function ($users) {
foreach ($users as $user) {
//
}
});
تستطيع إيقاف معالجة قطع أخرى عبر رد القيمة false
من Closure:
DB::table('users')->orderBy('id')->chunk(100, function ($users) {
// عالج السجلات...
return false;
});
المجاميع
يوفّر منشئ الاستعلامات أيضًا مجموعة متنوعة من التوابع التجميعية (aggregate methods) مثل count
، و max
، و min
، و avg
، و sum
. تستطيع مناداة أي من هذه التوابع بعد إنشاء استعلامك:
$users = DB::table('users')->count();
$price = DB::table('orders')->max('price');
تستطيع طبعًا دمج هذه التوابع مع بنود أخرى:
$price = DB::table('orders')
->where('finalized', 1)
->avg('price');
تحديد ما إذا كانت السجلات موجودة
تستطيع استخدام الأساليب exists
و doesntExist
بدل استخدام التابع count
لتحديد ما إذا طابقت أية سجلات قيود استعلامك:
return DB::table('orders')->where('finalized', 1)->exists();
return DB::table('orders')->where('finalized', 1)->doesntExist();
معاملات عرض السجلّات Selects
تحديد بند Select
قد لا ترغب دائمًا طبعًا في تحديد (select) كافة الأعمدة من جدول قاعدة البيانات. تستطيع تحديد بند select مُخصّص للاستعلام باستخدام التابع select
:
$users = DB::table('users')->select('name', 'email as user_email')->get();
يسمح لك التابع distinct
باجبار الاستعلام على ردّ النتائج الفريدة:
$users = DB::table('users')->distinct()->get();
تستطيع استخدام التابع addSelect
إن كان لديك نسخة منشئ استعلامات مسبقًا ورغبت في إضافة عمود آخر لعموده Select الحالي:
$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();
تعبيرات خام
قد تحتاج في بعض الأحيان لاستخدام تعبير خام في استعلام. تستطيع استخدام التابع DB::raw
لإنشاء تعبير خام:
$users = DB::table('users')
->select(DB::raw('count(*) as user_count, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
ملاحظة: ستُضاف التعابير الخامة للاستعلام كسلاسل نصيّة لذا عليك التزام الحذر الشديد كيلا تخلق نقاط ضعف حُقن SQL.
التوابع الخامة
تستطيع أيضًا استخدام التوابع التالية بدلاً من استخدام DB::raw
لإدراج تعبير خام في أجزاء مختلفة من استعلامك.
selectRaw
يمكن استخدام التابع selectRaw
بدلاً من select(DB::raw(...))
. يقبل هذا التابع مصفوفةً اختياريّةً من الارتباطات كمتغيّر وسيط ثاني لها:
$orders = DB::table('orders')
->selectRaw('price * ? as price_with_tax', [1.0825])
->get();
whereRaw / orWhereRaw
whereRaw
و orWhereRaw
هما تابعان يمكن استخدامها لإضافة بند where
خام لاستعلامك. تقبل هذه التوابع مصفوفة اختياريّة من الارتباطات كمتغيّر وسيط ثاني لها:
$orders = DB::table('orders')
->whereRaw('price > IF(state = "TX", ?, 100)', [200])
->get();
havingRaw / orHavingRaw
havingRaw
و orHavingRaw
هما تابعان يمكن استخدامها لتعيين سلسلة نصيّة خام كقيمة البند having. تقبل هذه التوابع مصفوفة اختيارية من الارتباطات كمتغيّر وسيط ثاني لها:
$orders = DB::table('orders')
->select('department', DB::raw('SUM(price) as total_sales'))
->groupBy('department')
->havingRaw('SUM(price) > ?', [2500])
->get();
orderByRaw
يمكن استخدام التابع orderByRaw
لتعيين سلسلة نصيّة خامة كقيمة البند order by:
$orders = DB::table('orders')
->orderByRaw('updated_at - created_at DESC')
->get();
معاملات ربط الجداول Joins
بند الربط الداخلي (Inner Join Clause)
يمكن استخدام منشئ الاستعلامات لكتابة تعابير الربط (join statements). لإجراء "ربط داخلي" بسيط، تستطيع استخدام التابع join
على نسخة منشئ استعلامات. أوّل متغيّر وسيط يُمرّر إلى التابع join
هو اسم الجدول الذي تحتاج للربط به في حين أن المُغيّرات الباقية تحدد قيود العمود للربط. تستطيع كما ترى الربط بعدّة جداول في استعلام واحد:
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();
بند الربط اليساري (Left Join Clause)
إن رغبت في عمل "ربط يساري" بدلاً من "ربط داخلي"، استخدم التابع leftJoin
. يملك التابع leftJoin
نفس توقيع التابع join
:
$users = DB::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->get();
بند الربط المُتقاطع (Cross Join Clause)
لعمل "ربط مُتقاطع"، استخدم التابع crossJoin
مع اسم الجدول الذي ترغب في الربط به. يولّد الربط المُتقاطع نتيجة ديكارتيّة بين الجدول الأول والجدول المربوط:
$users = DB::table('sizes')
->crossJoin('colours')
->get();
بنود الربط المتقدّمة
تستطيع أيضًا تحديد شروط ربط أكثر تقّدمًا. للبدء، مرّر Closure كالمتغيّر الوسيط الثاني في التابع join
. سيتلقّى Closure كائن JoinClause
والذي يسمح لك بتحديد القيود على البند join:
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);
})
->get();
تستطيع استخدام التابعين where
و orWhere
في الربط إن رغبت في استخدام شرط على نمط "where" في ارتباطاتك (joins). ستُقارن هذه التوابع العمود بالقيمة بدلاً من مقارنة عمودين ببعضهما:
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();
ربط الاستعلام الفرعي ( Sub-Query Joins)
تستطيع استخدام التوابع joinSub
leftJoinSub
و rightJoinSub
و rightJoinSub
لربط استعلام باستعلام فرعي. يتلقى كل تابع من هذه التوابع ثلاث مُتغيّرات وسيطة: الاستعلام الفرعي، واسم جدولها المستعار (table alias)، ونطاق مغلق يحدّد الأعمدة ذات الصلة: