Equivalent ORM Query in Laravel - laravel

Following is my query:
select nonrem_id as RefID , (SELECT group_concat(concat(nonremu_updated_date, ' - ',name,' - ',ttu.nonremu_updates) SEPARATOR ',') FROM `fanda_bank_nonremit_update` as ttu left join fanda_mst_users on login_id = nonremu_createdby WHERE ttu.nonremu_cid = fanda_bank_acc_nonremitted.nonrem_id order by ttu.nonremu_id asc ) as Comments from `fanda_bank_acc_nonremitted` left join `fanda_mst_users` on `login_id` = `nonrem_created_by` where `nonrem_gl_date` >= 2017-02-01 and `nonrem_gl_date` <= 2017-05-11 and `nonrem_country` = BE
How do I write this query in Laravel Eloquent ORM. I have tried using Query builder, but I wanna know how to write this query in pure ORM.
P.S: I should not use DB::raw() anywhere.
Kindly help.

You can't, you'll need DB::raw() to build a select statement like that.
EDIT:
If you don't care about using DB::raw() on your select, then try something like this on your select:
Model::select('nonrem_id as RefID',DB::raw('(SELECT group_concat(concat(nonremu_updated_date, ' - ',name,' - ',ttu.nonremu_updates) SEPARATOR ',') FROM `fanda_bank_nonremit_update` as ttu left join fanda_mst_users on login_id = nonremu_createdby WHERE ttu.nonremu_cid = fanda_bank_acc_nonremitted.nonrem_id order by ttu.nonremu_id asc ) as Comments'))
If you are using strict mode it will throw a QueryException cause you are ordering your first query by a non selected field , to avoid this query exception configure your db connection to allow this kind of order by. You can do it on the file: config/database.php by adding this two parameters to your actual connection within your 'connections' array:
'strict' => true,
'modes' => ['STRICT_TRANS_TABLES',
'NO_ZERO_IN_DATE',
'NO_ZERO_DATE',
'ERROR_FOR_DIVISION_BY_ZERO',
'NO_AUTO_CREATE_USER',
'NO_ENGINE_SUBSTITUTION'],

Related

Laravel - Get the last entry of each UID type

I have a table that has 100's of entries for over 1000 different products, each identified by a unique UID.
ID UID MANY COLUMNS CREATED AT
1 dqwdwnboofrzrqww1 ... 2018-02-11 23:00:43
2 dqwdwnboofrzrqww1 ... 2018-02-12 01:15:30
3 dqwdwnbsha5drutj5 ... 2018-02-11 23:00:44
4 dqwdwnbsha5drutj5 ... 2018-02-12 01:15:31
5 dqwdwnbvhfg601jk1 ... 2018-02-11 23:00:45
6 dqwdwnbvhfg601jk1 ... 2018-02-12 01:15:33
...
I want to be able to get the last entry for each UID.
ID UID MANY COLUMNS CREATED AT
2 dqwdwnboofrzrqww1 ... 2018-02-12 01:15:30
4 dqwdwnbsha5drutj5 ... 2018-02-12 01:15:317
6 dqwdwnbvhfg601jk1 ... 2018-02-12 01:15:33
Is this possible in one DB call?
I have tried using DB as well as Eloquent but so far I either get zero results or the entire contents of the Table.
Andy
This is easy enough to handle in MySQL:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT UID, MAX(created_at) AS max_created_at
FROM yourTable
GROUP BY UID
) t2
ON t1.UID = t2.UID AND
t1.created_at = t2.max_created_at;
Translating this over to Eloquent would be some work, but hopefully this gives you a good starting point.
Edit: You may want to use a LEFT JOIN if you expect that created_at could ever be NULL and that a given UID might only have null created values.
You can use a self join to pick latest row for each UID
select t.*
from yourTable t
left join yourTable t1 on t.uid = t1.uid
and t.created_at < t1.created_at
where t1.uid is null
Using laravel's query builder it would be similar to
DB::table('yourTable as t')
->select('t.*')
->leftJoin('yourTable as t1', function ($join) {
$join->on('t.uid','=','t1.uid')
->where('t.created_at', '<', 't1.created_at');
})
->whereNull('t1.uid')
->get();
Laravel Eloquent select all rows with max created_at
Laravel Eloquent group by most recent record
SELECT p1.* FROM product p1, product p2 where p1.CREATED_AT> p2.CREATED_AT group by p2.UID
You can achieve this with eloquent using orderBy() and groupBy():
$data = TblModel::orderBy('id','DESC')->groupBy('uid')->get();
SOLVED
Thanks to Tim and M Khalid for their replies. It took me down the right road but I hit a snag, hence why I am posting this solution.
This worked:
$allRowsNeeded = DB::table("table as s")
->select('s.*')
->leftJoin("table as s1", function ($join) {
$join->on('s.uid', '=', 's1.uid');
$join->on('s.created_at', '<', 's1.created_at');
})
->whereNull('s1.uid')
->get();
However I got an Access Violation so I had to go in to config/database.php and set
'strict' => false,
inside the 'mysql' config, which removes ONLY_FULL_GROUP_BY from the SQL_MODE.
Thanks again.
You have to use ORDER BY, and LIMITSQL parameters, which will lead you to an easy SQL request :
for exemple, in SQL you should have something like this :
SELECT *
FROM table_name
ORDER BY `created_at` desc
LIMIT 1
This will returns everything in the table. The results will be ordering by the column "created_at" descending. So the first result will be what you're looking for. Then the "LIMIT" tells to return only the first result, so you won't have all your database.
If you wanna make it with eloquent, here is the code doing the same thing :
$model = new Model;
$model->select('*')->orderBy('created_at')->first();

Ecto Model - subquery in select

I need to make this SQL query with Ecto:
SELECT users.*, (select count(0) from money_transactions where from_id = users.id AND created_at > '2016-1-25 0:00:00.000000') as money_transactions_today_db FROM "users" WHERE "users"."client_token" = '123'
I try to do something like this but it doesn't work:
query = from users in Like4uElixir.User,
where: users.client_token in ^tokens,
select: {users, (from money_transactions in Like4uElixir.MoneyTransaction,
where: money_transactions.from_id == users.id,
select: count(0))}
Does Ecto support subqueries? If not, how can I execute the query?
You can use query fragments:
query = from users in Like4uElixir.User,
where: users.client_token in ^tokens,
select: {users, (fragment("(SELECT COUNT(0) FROM money_transactions
WHERE money_transactions.from_id == ?)", users.id))}
Although in this case the query can also be written using regular joins and group_by. Current support for subqueries in Ecto is limited.

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.

Subqueries in Doctrine 1.2 DQL as FROM

Ok so the big deal is to get the rows in a mysql table that have another related row in the same table given some conditions. This table is like an activity log, so i want to notify someone that "some guy" leaved his group, but i only want do the notification when that guy joined the group before a given date, so what i do is the next sql:
SELECT ua.*, ua2.*
FROM user_activities AS ua
INNER JOIN (SELECT ua2.* FROM user_activities AS ua2
WHERE ua2.activity = "join-group"
ORDER BY ua2.created_at)
AS ua2 ON ua2.group_name = ua.group_name AND ua2.user_id = ua.user_id
WHERE ua.activity = "unjoin-group";
I omitted the date conditions due to clarity reasons.
So i need to know how to convert this to DQL (for doctrine 1.2), is it possible? or I better do it programatically?
What im trying now is this:
$q = Doctrine_Query::create()
->from('UserActivity ua, ua.User u ')
->where('ua.created_at > ?', $min_date)
->andWhere('ua.activity = ?', "unjoin-group")
->andWhereIn('u.status', array(STATUS_HOT, STATUS_ACTIVE))
->andWhere('ua.user_id IN ( SELECT
uaa.id
FROM
UserActivity uaa
WHERE
uaa.activity = ? AND
uaa.created_at < ? AND
uaa.created_at > ? AND
uaa.group_name = ua.group_name
LIMIT 1',
array("join-group", $min_date, $max_date));
But i get this error:
fatal error maximum function nesting level of '100' reached aborting
So i can't keep foward

SQL to LINQ query asp.net

I am currently trying to get some statistics for my website but i cant seem to create the query for my database to get the username that if found most frequent in all the rows.
The sql query should look something like this:
SELECT username FROM Views GROUP BY 'username' ORDER BY COUNT(*) DESC LIMIT 1
How do i make that query in my controller?
var username = db.Views.GroupBy(v => v.username).OrderByDescending(g => g.Count()).First().Key
(from a in Views
group a by a.username into b
let c = b.count()
orderby c descending
select a.username).take(1);
Your query conversion .....
This is how you do that query using LINQ:
var temp = (from a in Views
group a.username by a.username into b
orderby b.Count() descending
select b.Key).Take(1);
You can't do LIMIT 1 (mysql), since LinqToSql only generates TSql from MSSqlServer.

Resources