Select rows having 2 columns equal value in laravel Query builder - laravel

I want to write a query which selects rows where 2 attributes from 1 entity have equal value.
This would be an example of doing this in raw SQL:
Select * from users u where u.username = u.lastname
Does laravel have any methods that take 2 column names as parameters and return the matching results?

What you need is a DB::raw expression:
DB::table('users')
->where('username', '=', DB::raw('lastname'))
->get();
The only thing DB::raw actually does is to tell the query interpreter not to treat 'lastname' like any other string value but just interpolate it in the SQL as it is.
http://laravel.com/docs/queries#raw-expressions

In Laravel 5, there's now whereColumn for this, for cleaner code:
Users::whereColumn('username', 'lastname')->get();

Related

problem of syntax in where clause when 2 columns are equal?

I have a filter on a form before displaying a list.
If the filter 'filter_parisetat' = 2, i set the where clause like this :
$query = $query->where('gri_nb_matchs','gri_nb_matchs_pec');
I want to select all the rows of my Grille table where 'gri_nb_matchs' equals 'gri_nb_matchs_pec'
but it doesn't work..nothing is selected (and of course in my table I have 10 in each columns for these 2 fields
The other Where conditions in case 1 is equal to
$query = $query->where('gri_nb_matchs','>','gri_nb_matchs_pec');
I should retrieve 0 rows, but here I retrieve all the rows..
it works upside down...
In My table, the 2 fields are described like this :
11 gri_nb_matchs tinyint(3) UNSIGNED
12 gri_nb_matchs_pec tinyint(3) UNSIGNED
In MySql, whenI write the query, results are correct..
What went wrong ?
Thanks a lot
Thierry
In this statement:
$query = $query->where('gri_nb_matchs','>','gri_nb_matchs_pec');
It seems you are comparing the field gri_nb_matchs to the string value 'gri_nb_matchs_pec', not the column named gri_nb_matchs_pec. In order to achieve this you have to use a raw query as so:
$query = $query->where('gri_nb_matchs','>',DB::raw('gri_nb_matchs_pec'));
or
$query = $query->whereRaw('gri_nb_matchs > gri_nb_matchs_pec');

Eloquent: Order by sum of two columns

My working SQL query is as follows:
SELECT post_id
FROM news_tags
ORDER BY (link_clicks+views) DESC
What I've tried so far in eloquent is like this:
$newsTagSaved = NewsTag::
orderBy(DB::raw("`views` + `link_clicks`"), 'desc')
->paginate(12)
->pluck('post_id');
Newstag table has many columns and views and link_clicks are two of them. Now, I'm trying to retrieve the post_id order by desc of sum of views and link_click.
How can I do it in Laravel eloquent?
Thank you!
Do something like this:
$newsTagSaved = NewsTag::select(DB::raw('views + link_clicks as score'))
->orderBy('score', 'desc')
->get();
dd($newsTagSaved);
This will return just score value. If you want to return other fields, simply add them to select. As an example:
$newsTagSaved = NewsTag::select(
DB::raw('views + link_clicks as score'),
'title',
'created_at'
)
->orderBy('score', 'desc')
->get();
dd($newsTagSaved);

date method in eloquent querybuilder

i have this raw query and i want to use it in eloquent query builder
but seems i cant use date method in eloquent and gave me this error im new in eloquent. what is the problem:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'date(prizes.created_at), user_id' in 'group statement' (SQL: select user_id,COUNT(user_id), date(created_at) from `prizes` group by `date(prizes`.`created_at), user_id` having `user_id` = 1 order by `date(created_at)` desc)
raw SQL:
SELECT
user_id,COUNT(user_id), DATE(created_at) FROM prizes
GROUP BY DATE(prizes.created_at), user_id
HAVING user_id = 1
ORDER BY DATE(created_at) DESC
limit 2
Eloquent:
$points = \App\Prize::selectRaw('user_id,COUNT(user_id), date(created_at)')
->groupBy("date(prizes.created_at), user_id")
->orderBy("date(created_at)","DESC")
->having("user_id","=",1)
->get();
what is the the cleanest and best form??
By default, Laravel tries to parse all strings as tables. This means it will add the string between `.
To avoid this, you can put the string in a DB:raw() function to let Laravel know not to parse this string and send it as-is to the database.
->orderBy(\DB::raw("date(created_at)"), "DESC")
Or use the raw method for ordering:
->orderByRaw('date(created_at) desc')

In Laravel Eloquent, how do I reference primary query in subquery

I have a model User that has many Orders. Orders have many products, with the pivot table order-product. I don't want to preload and iterate through the orders if at all possible.
I need to return users where
signed_date === true on User
order_date on Order is after signed_date on User
order-product shows product hasn't been paid
I am failing on number 2.
In the following code, the first query within whereHas is wrong. I don't know how to reference the signed date of the user from within the where has. If I was iterating through users in a collection I could do something like ($query) use $user, but how do I do this without preloading all the users?
return User::whereNotNull('signed_date')
->whereHas('orders', function ($query) {
$query->where('order_date', '<=', 'user.signed_date');
$query->whereHas('products', function ($q) {
$q->where('paid', false);
});
})
->get(['id','fname','lname', 'title', 'signed_date']);
I would like to use eloquent if possible. If that is not possible, I would be happy for tips in solving this problem using the query builder/sql.
The Eloquent query builder has a special function called whereColumn('a', '<=', 'b') to compare columns instead of a column against a value. Using this function instead of a normal where() is necessary because of the way the query builder builds the actual query. You need to let the query builder know that you are going to pass a column name instead of a value for proper escaping and formatting of the query string.
Anyway, it seems you can also pass column names prefixed with a table name to the function, allowing you to compare columns across tables:
$query->whereColumn('orders.order_date', '<=', 'users.signed_date')
This works because you are using whereHas() in your query. Your query basically gets translated to:
SELECT id, fname, lname, title, signed_date
FROM users
WHERE signed_date NOT NULL
AND EXISTS (
SELECT 1
FROM orders
WHERE orders.order_date <= users.signed_date
AND EXISTS (
SELECT 1
FROM products
WHERE paid = 0
)
)
It might actually be not necessary at all to use the table name together with the column name in whereColumn(). But in case you'll ever add a column named the same on another table, the query might break - so IMHO it is good practice to use the table name in custom queries.
By the way, the reason this will not work together with with('relationship') is that this function results in an additional query and you obviously cannot compare columns across queries. Imagine the following:
Order::with('user')->take(5)->get();
It will be translated into the following:
SELECT *
FROM orders
LIMIT 5
SELECT *
FROM users
WHERE id IN (?, ?, ?, ?, ?)
where the five ? will be the user_ids of the orders. If the first query returns multiple rows with the same user_id, the amount of rows fetched from the users table gets reduced of course.
Note: All the queries are only examples. Might be that the query builder builds different queries based on the database type and/or escapes them differently (i.e. column names in backticks).

Eloquent query alternative

How can I write the following in Laravel's Eloquent?
SELECT *
FROM
( SELECT real_estate.property_id,
real_estate.amount_offered,
payee.summa
FROM real_estate
LEFT JOIN
(SELECT property_id,
SUM(amount) AS summa
FROM payments
GROUP BY property_id) payee ON payee.property_id = real_estate.property_id ) yoot
WHERE summa = 0.05 * amount_offered
Been on this for a while now and really can't get around it. Lemme explain the whole cause for the panic.
I have two tables, one for property and another for payments made on those properties. Now at any given time I will like to query for what properties have been paid for to a certain percentage hence the 0.05 which reps 5%. As it is the query works but I need an Eloquent alternative for it. Thanks
Anywhere you have subqueries in your SQL you'll need to use DB::raw with Eloquent. In this case you have a big subquery for the FROM statement, so the easiest way would be to do this:
DB::table(
DB::raw('SELECT real_estate.property_id, real_estate.amount_offered, payee.summa FROM real_estate LEFT JOIN (SELECT property_id, SUM(amount) AS summa FROM payments GROUP BY property_id) payee ON payee.property_id = real_estate.property_id)')
)
->where('summa', DB::raw('0.05 * amount_offered'))->get();
Notice I used DB::raw for the WHERE statment value as well. That's because you are doing a multiplication using a column name, and the value would otherwise be quoted as a string.
If you want to go a step further and build each subquery using Eloquent, then convert it to an SQL string and injecting it using DB::raw, you can do this:
$joinQuery = DB::table('payments')
->select('property_id', 'SUM(amount) AS summa')
->groupBy('property_id')
->toSql();
$tableQuery = DB::table('real_estate')
->select('real_estate.property_id', 'real_estate.amount_offered', 'payee.summa')
->leftJoin(DB::raw('(' . $joinQuery . ')'), function ($join)
{
$join->on('payee.property_id', '=', 'real_estate.property_id');
})
->toSql();
DB::table(DB::raw('(' . $tableQuery . ')'))->where('summa', DB::raw('0.05 * amount_offered'))->get();
In this case, the second approach doesn't have any benefits over the first, except perhaps that it's more readable. However, building subqueries using Eloquent, does have it's benefitfs when you'd need to bind any variable values to the query (such as conditions), because the query will be correctly built and escaped by Eloquent and you would not be prone to SQL injection.

Resources