Laravel query build based on relation - mysql

I have such query:
Tournament::has('participations', '<', '2')->get();
How can I replace constant number '2' on tournament's column named slots ?? I would like retrieve only these tournaments which have least participants than slots in tournament.

Let's start by using the column name instead of "2". Like you would do in "normal" SQL
Tournament::has('participations', '<', 'slots')->get();
Now, you don't even have to try that because it won't work. But why's that? Because Laravel treats slots like a string and escapes it so SQL does as well.
What you need to do, is use DB::raw(). raw makes sure Laravel changes nothing and just injects it into the SQL query
Tournament::has('participations', '<', DB::raw('slots'))->get();
Update
After some trying out I found this: (Its not very pretty but the only way I got it working)
$subquery = function($q) use ($uid){
$q->where('player_id', $uid);
}
Tournament::whereHas('participations', $subquery)
->whereHas('participations', $subquery, '<', DB::raw('slots'))
->get();
The first whereAs checks for count(*) > 0, the second count(*) < slots and the subquery filters by player id.

Related

how to search by letter in column in database (laravel)

I want to find by letter customer's first_name on my 'customers' table.
And the only thing that I get is an empty array.
For instance, I put in the parameter 'q' value 'E' to get customer Elena from my database by I get an only empty array.
I use the following code to get first_name :
$search = Input::get('q');
if($search)
{
$customers = Customer::all()->where('full_name', 'LIKE', "%{$search}%");
return ($customers);
}
Can someone help me?
Your query don't work because you are calling the all() method before the where(). That's actually not wrong, but it have different behavior.
When you call all(), it actually does the SQL query. After that, any chained methods are being called into a Eloquent Collection class, and it also have a where method, but that's simpler since it runs on PHO instead of running on SQL.
Since the collection's where() method doesn't support LIKE operator, it's probably searching for a value that is exactly %E%.
Hope it can help you understanding why your query doesn't work as expected.
Try this
$customers = Customer::where('full_name', 'LIKE', "%{$search}%")->get();
Laravel Eloquent

Laravel db query with now()

I need to take data from DB, but only when ReturnDate column represents date in the future.
When i do SQL query from DB its working
SQL code:
SELECT * FROM `injuries_suspensions` WHERE `Type` = 'injury' and NOW() < `ReturnDate`
But when i use similar version in Laravel DB query builder, i dont get any data (when i erase where with NOW() i get all data so thats the problem)
Lravel code:
$injuries = DB::table('injuries_suspensions')->where('Type', '=', 'injury')->where(DB::raw('NOW()'), '<', 'ReturnDate')->get();
P.S
dates in DB are far in the future 2020-11-30.
You want to use the simplified version whereRaw instead:
$injuries = DB::table('injuries_suspensions')
->where('Type', '=', 'injury')
->whereRaw('ReturnDate > NOW()')->get(); //see I changed the comparison sides
Observation is that, you're not using whereRaw properly: all should be inside a single string see laravel's example.
You can also pass the timestamp/date directly when building the query, using Carbon see:
use Carbon/Carbon;
....
$injuries = DB::table('injuries_suspensions')
->where('Type', '=', 'injury')
->where('ReturnDate', '>', Carbon::now()->toDateTimeString())->get();
PS: Beware though of timezone difference of your db and your server.

Laravel 5.3 Query - Left join some table

I'm trying to get the most recent record for each candidate_id from a ìnterviews` table.
This is what I want to achive:
I'm using Eloquent on laravel and have already tried this methods (with and without eloquent):
$candidates = DB::table('interviews')->select('interviews.*', 'i2.*')
->leftJoin('interviews as i2',
function ($join) {
$join->on('interviews.candidate_id', '=', 'i2.candidate_id');
$join->on('interviews.created_at', '<', 'i2.created_at');
}
)
->whereNull('i2.candidate_id')
->get();
and with eloquent I've tried this:
$candidates = Interview::leftJoin('interviews as i2',
function ($join) {
$join->on('interviews.candidate_id', '=', 'i2.candidate_id');
$join->on('interviews.created_at', '<', 'i2.created_at');
}
)->whereNull('i2.candidate_id')
->get();
If I change get() to toSql() I have exactly the same query that's shown on the above image, but running on laravel I'm getting always these results (this using the first method, with query builder):
Anyone know why I get this results? Is hard to understand that laravel is doing the same query that I do in HeidiSql but I get diferent results :(
Any tip?
Thanks in advance!
Because you are using ->select('interviews.*', 'i2.*') combined with ->whereNull('i2.candidate_id') I am assuming the second select parameter is overriding all fields on the interviews table with nulls, try reversing the order to ->select('i2.*','interviews.*') or not use the i2.* at all.
This is because the output ignores the alias and only uses the fieldname as element key in the returned collection.
Hope it works.
Perfect case scenario you pick the exact columns you want from each of the joined tables for e.g. it may go like this: table1.id,table1.column1,table1.column2,table2.column2 as smth_so_it_doesnt_override

Eloquent count distinct returns wrong totals

i'm having an issue with how eloquent is formulation a query that i have no access to. When doing something like
$model->where('something')
->distinct()
->paginate();
eloquent runs a query to get the total count, and the query looks something like
select count(*) as aggregate from .....
The problem is that if you use distinct in the query, you want something like
select count(distinct id) as aggregate from .....
to get the correct total. Eloquent is not doing that though, thus returning wrong totals. The only way to get the distinct in count is to pass an argument through the query builder like so ->count('id') in which case it will add it. Problem is that this query is auto-generated and i have no control over it.
Is there a way to trick it into adding the distinct on the count query?
P.S Digging deep into the builders code we find an IF statement asking for a field on the count() method in order to add the distinct property to the count. Illuminate\Database\Query\Grammars\BaseGrammar#compileAggregate
if ($query->distinct && $column !== '*')
{
$column = 'distinct '.$column;
}
return 'select '.$aggregate['function'].'('.$column.') as aggregate';
P.S.1 I know that in SQL you could do a group by, but since i'm eager loading stuff it is not a good idea cause it will add a IN (number of id's found) to each of the other queries which slows things down significantly.
I faced the exact same problem and found two solutions:
The bad one:
$results = $model->groupBy('foo.id')->paginate();
It works but it will costs too much memory (and time) if you have a high number of rows (it was my case).
The better one:
$ids = $model->distinct()->pluck('foo.id');
$results = $query = $model->whereIn('foo.id', $ids)->paginate();
I tried this with 100k results, and had no problem at all.
This seems to be a wider problem, discussed here:
https://github.com/laravel/framework/issues/3191
https://github.com/laravel/framework/pull/4088
Untill the fixes are shipped with one of the next Laravel releases, you can always try using the raw expressions, like below (I didnt test it, but should work)
$stuff = $model->select(DB::raw('distinct id as did'))
->where('whatever','=','whateverelse')
->paginate();
Reference: http://laravel.com/docs/queries#raw-expressions
$model->where('something')->distinct()->count('id')->paginate();

Using a table-alias in Kohana queries?

I'm trying to run a simple query with $this->db in Kohana, but am running into some syntax issues when I try to use an alias for a table within my query:
$result = $this->db
->select("ci.chapter_id, ci.book_id, ci.chapter_heading, ci.chapter_number")
->from("chapter_info ci")
->where(array("ci.chapter_number" => $chapter, "ci.book_id" => $book))
->get();
It seems to me that this should work just fine. I'm stating that "chapter_info" ought to be known as "ci," yet this isn't taking for some reason. The error is pretty straight-forward:
There was an SQL error: Table 'gb_data.chapter_info ci' doesn't exist -
SELECT `ci`.`chapter_id`, `ci`.`book_id`, `ci`.`chapter_heading`,
`ci`.`chapter_number`
FROM (`chapter_info ci`)
WHERE `ci`.`chapter_number` = 1
AND `ci`.`book_id` = 1
If I use the full table name, rather than an alias, I get the expected results without error. This requires me to write much more verbose queries, which isn't ideal.
Is there some way to use shorter names for tables within Kohana's query-builder?
In Kohana 3 it is simply enough:
->from( array('table_name', 'alias') )
and this will create the query that contains:
FROM 'table_name' AS 'alias'
I have tested it and it works. Good luck.
$result = $this->db
->select("ci.chapter_id, ci.book_id, ci.chapter_heading, ci.chapter_number")
->from("'chapter_info' AS ci")
->where(array("ci.chapter_number" => $chapter, "ci.book_id" => $book))
->get();
That should work. As you must wrap the original table name in quotes first before the AS keyword and the new table name you want to shorten it to.
Try using the "as" keyword like ->from("chapter_info as ci"), maybe the query builder will recognize it this way.