Znamy już subqueries w SQLu, pora nauczyć się je robić w Laravelu. Do dzieła.
Ok, wykonajmy ten kod w naszej bazie danych:
SELECT COUNT(rating)
from `reviews`
where rating = (SELECT min(rating) from `reviews`);
Już to robiliśmy, ale mam nadzieję, że pamiętamy. Teraz to samo zrobimy w Laravelu z fasadą DB:
Artisan::command('reviews-min-cnt', function () {
$cnt = DB::table('reviews')
->select(DB::raw('count(rating) as cnt'))
->whereRaw('rating = (SELECT min(rating) from `reviews`)')
->get()->toArray();
$this->comment("Reviews with min rating: {$cnt[0]->cnt}");
});
Nie wygląda to najpiękniej, ale działa. Ok, inny kod SQL:
SELECT *
FROM `movies`
WHERE director like "Prof.%";
Nieco inny patent na w zasadzie to samo, funkcja INSTR:
SELECT *
FROM `movies`
WHERE INSTR(director, "Prof.");
Ok, teraz użyjemy tego jako subquery:
SELECT *
FROM `reviews`
WHERE movie_id in
(SELECT id
FROM `movies`
WHERE director like "Prof.%"
);
No i teraz cała magia Laravela, który wcale nie nakazuje nam robić ->get() i z odpowiednią metodą możemy mieć subquery bardzo prosto:
Artisan::command('movies-prof', function () {
$professors = DB::table('movies')
->select('id')
->where('director', 'like', 'Prof.%');
$reviews = DB::table('reviews')
->whereIn('movie_id', $professors)
->get();
foreach($reviews as $r){
$this->comment("Movie id: {$r->movie_id} rating: {$r->rating}");
}
});
Mamy też metodę whereLike, warto również jej użyć:
Artisan::command('movies-prof2', function () {
$professors = DB::table('movies')
->select('id')
->whereLike('director', 'Prof.%');
$reviews = DB::table('reviews')
->whereIn('movie_id', $professors)
->get();
foreach($reviews as $r){
$this->comment("Movie id: {$r->movie_id} rating: {$r->rating}");
}
});
A gdybyśmy chcieli użyć funkcji INSTR, to jak w przypadku każdej funkcji w fasadzie DB musimy użyć raw, w tym wypadku whereRaw:
Artisan::command('movies-prof3', function () {
$professors = DB::table('movies')
->select('id')
->whereRaw('INSTR(director, "Prof.")');
$reviews = DB::table('reviews')
->whereIn('movie_id', $professors)
->get();
foreach($reviews as $r){
$this->comment("Movie id: {$r->movie_id} rating: {$r->rating}");
}
});
Mamy też metodę whereNotIn:
Artisan::command('movies-not-prof', function () {
$professors = DB::table('movies')
->select('id')
->whereRaw('INSTR(director, "Prof.")');
$reviews = DB::table('reviews')
->whereNotIn('movie_id', $professors)
->get();
foreach($reviews as $r){
$this->comment("Movie id: {$r->movie_id} rating: {$r->rating}");
}
});
I oczywiście nikt nie każe nam tych metod używać w subqueries:
$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();
$users = DB::table('users')
->whereNotIn('id', [1, 2, 3])
->get();
Mam nadzieję, że nie przeraża nas fasada DB (ani SQL), Query Builder to taka sama część Laravela jak Eloquent i trzeba dobrze znać jedno i drugie (+ czysty SQL).