how to translate this mysql code in laravel - mysql

I get 3 tables in my database. I want to know how to translate this mysql query in laravel. Here is the code:
SELECT item.id, item.libelle, entre.item_id, entre.total AS etotal, entre.prix_unitaire AS eprix, sortie.total AS stotal, sortie.prix_unitaire AS sprix, (entre.total - sortie.total) AS restant
FROM (
SELECT id, libelle
FROM items
WHERE EXISTS (
SELECT *
FROM entrees
WHERE items.id = entrees.item_id
AND date_entree = '23-10-2019'
)
) item
LEFT JOIN (
SELECT item_id, prix_unitaire, sum(total) total
FROM entrees
WHERE date_entree = '23-10-2019'
GROUP BY item_id
) entre ON item.id = entre.item_id
LEFT JOIN (
SELECT item_id, prix_unitaire, sum(total) total
FROM sorties
GROUP BY item_id
) sortie ON entre.item_id = sortie.item_id;
For table entrees enter image description here
For table items enter image description here
For table sortiesenter image description here
So please help me. And if possible explain me the query cause honestly I found it on another forum

First let's break down your query into all the subqueries and then write them all together.
Subquery 1
SELECT id, libelle
FROM items
WHERE EXISTS (
SELECT *
FROM entrees
WHERE items.id = entrees.item_id
AND date_entree = '23-10-2019'
)
Translated to Query Builder:
$subquery1 = DB::table('items')
->select('id', 'libelle')
->whereExists(function ($query) {
$query->from('entrees')
->whereColumn('items.id', 'entrees.item_id')
->where('date_entree', '23-10-2019');
});
// You can verify this by dumping $subquery1->toSql() in the console.
Subquery 2
SELECT item_id, prix_unitaire, sum(total) total
FROM entrees
WHERE date_entree = '23-10-2019'
GROUP BY item_id
Translated to Query Builder:
$subquery2 = DB::table('entrees')
->select('item_id', 'prix_unitaire')
->selectRaw('sum(total) as total')
->where('date_entree', '23-10-2019')
->groupBy('item_id');
// You can verify this by dumping $subquery2->toSql() in the artisan console.
Subquery 3
SELECT item_id, prix_unitaire, sum(total) total
FROM sorties
GROUP BY item_id
Translated to Query Builder:
$subquery3 = DB::table('sorties')
->select('item_id', 'prix_unitaire')
->selectRaw('sum(total) as total')
->groupBy('item_id');
// You can verify this by dumping $subquery3->toSql() in the artisan console.
Now, to put it all together:
$query = DB::table($subquery1, 'item')
->select(
'item.id',
'item.libelle',
'entre.item_id',
'entre.total as etotal',
'entre.prix_unitaire as eprix',
'sortie.total as stotal',
'sotrie.prix_unitaire as sprix'
)
->selectRaw('(entre.total - sortie.total) as restant')
->leftJoinSub($subquery2, 'entre', function ($join) {
$join->on('item.id', '=', 'entre.item_id');
})
->leftJoinSub($subquery3, 'sortie', function ($join) {
$join->on('entre.item_id', '=', 'sortie.item_id');
});
// You can verify this by dumping $query->toSql() in the artisan console.
// To get the results, simply append the ->get() to the $query or do $query->get();
Below is a screen capture of this code being tested in the artisan console. The reason I'm using $db-> instead of DB:: is because I ran the following line before:
$db = DB::connection('mysql');
which makes sure the query is translated to mysql when I use toSql(). Pay it no mind.
Everything I used can be found in the official documentation about queries.

Related

Using coalesce with sequelize on node.js

I have the following query:
select coalesce(round(sum(vdamesatual) /
(select count(*)
from feriados
where month(data)=month(current_date) and
day(data)<day(current_date) and
diadasemana in(2,3,4,5,6) and
feriadonacional=0 and
uf <> (select distinct uforigem from baseprodutos where Empresa = 'test'))
*
(select count(*)
from feriados
where month(data)=month(current_date) and
day(data)>=day(current_date) and
diadasemana in(2,3,4,5,6) and
feriadonacional=0 and
uf <> (select distinct uforigem from baseprodutos where Empresa = 'test'))),0) as projecao
from baseprodutos
where Empresa = 'test' and
UFDest = 'uf' and
Fabricante = 'sample';
As you can see I have a coalesce right after the first select, and I am having trouble finding the right way to write this with sequelize; Would you have some suggestion?
I don't really follow the logic of your query, but the rule in Sequelize is that you can call any function with sequelize.fn() so a simple example of using COALESCE in Sequelize to get a value from 2 columns with an alias would be like this in your attributes:
[[sequelize.fn('COALESCE', mysql.col('col_name'), mysql.col('col_2_name')), 'alias'], 'another_col']
You can include another function if needed, like SUM by doing like this:
[[sequelize.fn('COALESCE', sequelize.fn('SUM', (mysql.col('col_name'), mysql.col('col_2_name'))), (some other code here ...)),'alias']]

raw SQL to laravel query builder

How do you convert this raw sql builder to laravel DB Builder
SELECT *
FROM `applications`
WHERE EXISTS (SELECT *
FROM `applicants`
INNER JOIN `applicant_application`
ON `applicants`.`id` =
`applicant_application`.`applicant_id`
WHERE `applications`.`id` =
`applicant_application`.`application_id`
AND `user_id` = 18)
ORDER BY `created_at` DESC
LIMIT 20
This is what I've tried but doesn't seem to work
DB::table('applications as apt')
->whereExists( function ($q) {
$q->from('applicants as app')
->join('applicant_application as aa', 'app.id', '=', 'aa.applicant_id')
->where('apt.id', '=', 'aa.application_id')
->where('app.user_id', '=', 18);
})->orderBy('created_at', 'DESC')->paginate(10);
Would appreciate any help
Because apt.id and aa.application_id are two columns from diff tables, and you are using where to compare the apt.id with string 'aa.application_id'.
You need to use whereColumn to compare two different columns:
->whereColumn('apt.id', '=', 'aa.application_id')

Laravel Eloquent with two “WHERE NOT IN” in subquery

I have this query that I am having trouble to write query in laravel eloquent ORM.
Appreciate if someone can help.
Here is SQL Expression:
SELECT DISTINCT cust, cust_no FROM delivery_sap
WHERE cust NOT IN ( SELECT cust_name FROM customer)
AND cust_no NOT IN ( SELECT cust_code FROM customer)
Instead of executing 3 different queries you can use like shown below,
DB::table('delivery_sap')
->whereNotIn('cust', function ($query) {
$query->select('cust_name')->from('customer');
})
->whereNotIn('cust_no', function ($query) {
$query->select('cust_code')->from('customer');
})
->select('cust', 'cust_no')
->distinct('cust')
->get();
This code will give the exact same query which is asked in the question,
to check the query, use following code
DB::table('delivery_sap')
->whereNotIn('cust', function ($query) {
$query->select('cust_name')->from('customer');
})
->whereNotIn('cust_no', function ($query) {
$query->select('cust_code')->from('customer');
})
->select('cust', 'cust_no')
->distinct('cust')
->toSql();
Output will be,
select distinct `cust`, `cust_no` from `delivery_sap`
where `cust` not in (select `cust_name` from `customer`)
and `cust_no` not in (select `cust_code` from `customer`)
Try Something like this:
DB::table('delivery_sap')
->whereNotIn('cust', DB::table('customer')->pluck('cust'))
->whereNotIn('cust_no', DB::table('customer')->pluck('cust_no'))
->select('cust', 'cust_no')
->groupBy('cust', 'cust_no')
->get();
I corrected the code below pluck('cust') to pluck('cust_name') and
pluck('cust_no') to pluck('cust_code') and it works
DB::table('delivery_sap')
->whereNotIn('cust', DB::table('customer')->pluck('cust_name'))
->whereNotIn('cust_no', DB::table('customer')->pluck('cust_code'))
->select('cust', 'cust_no')
->groupBy('cust', 'cust_no')
->get();
You could use exists or left join for better performance instead of sub queries on same table like in existing solution, there is no need for these 2 extra sub queries
SELECT DISTINCT cust, cust_no
FROM delivery_sap d
WHERE EXISTS (
SELECT 1
FROM delivery_sap
WHERE cust_name = d.cust OR cust_code = d.cust
)
OR
SELECT DISTINCT d.cust, d.cust_no
FROM delivery_sap d
LEFT JOIN delivery_sap d1 ON d.cust = d1.cust_name OR d.cust = d1.cust_code
WHERE d1.cust IS NULL
DB::table('delivery_sap as d')
->leftJoin('delivery_sap as d1', function ($join) {
$join->on('d.cust','=','d1.cust_name')
->orWhere('d.cust', '=', 'd1.cust_code');
})
->whereNull('d1.cust')
->select('cust', 'cust_no')
->distinct()
->get();

Eloquent query building complex query to get unique records searching for an ID in 2 different columns in same table

I'm migrating a project to Laravel 4 and I am stuck with a quite complex query, which I'd like to migrate into a proper Eloquent query.
I have a table that contains chat messages, called chat_messages with a representing Model Chatmessage
The table contains a sender and a receipient column with a user id linking to the users table and User Model.
The query to get a list with all user IDs of all chat partners in raw SQL on the old version of the application is as follows:
$sql_allChatPartners = "SELECT DISTINCT chatPartner
FROM ( SELECT * FROM (
SELECT cm_receipient AS chatPartner, cm_sent_at
FROM chat_messages WHERE cm_sender = '".$me->userID."'
UNION
SELECT cm_sender AS chatPartner, cm_sent_at
FROM chat_messages WHERE cm_receipient = '".$me->userID."'
) whateva ORDER BY whateva.cm_sent_at DESC ) other";
Sorry for naming the "fake" tables whateva and other :-)
Could anyone put me in the right direction to do this with Eloquent Querybuilder?
It is important that I get the list of chatPartner IDs in the correct order, where the last chat message has been exchanged as first chatPartner. And the chatPartner where longest inactivity was in the chat as last entry.
This is what I got so far in my User Model...
public function allopenchats(){
$asSender = Chatmessage::where('sender', $this->id)->select('receipient as chatPartner, created_at');
$asBoth = Chatmessage::where('receipient', $this->id)->select('sender as chatPartner, created_at')
->union($asSender)->orderBy('created_at', 'desc')->get();
}
I renamed the columns cm_receipient to receipient, cm_sender to sender and sent_at to created_at in the new database for the new version
Your help would be very much appreciated!
You sql may change to:
SELECT IF (cm_receipient = '10', cm_sender, IF (cm_sender = '10',cm_receipient, 'no')) AS chatPartner, cm_sent_at
FROM chat_messages
WHERE cm_receipient = '10' OR cm_sender = '10'
GROUP BY chatPartner
HAVING chatPartner != 'no'
order by cm_sent_at DESC
In orm:
Chatmessage::where('sender','=',$this->id)
->orWhere('receipient','=',$this->id)
->select(DB::raw('IF (receipient = '.$this->id.', sender, IF (sender = '.$this->id.',receipient, 'no' )) AS chatPartner'), 'created_at')
->groupBy('chatPartner')
->having('chatPartner', '!=', 'no')
->orderBy('created_at', 'desc')
->get();
Thanks very much to Vitalik_74, I wouldn't have come that far without him.
Here is now the final query, although its not in ORM, but it is working fine and gives me the result I need.
$result = DB::select("SELECT *
FROM (
SELECT IF( receipient = '".$this->id."', sender, IF( sender = '".$this->id."', receipient, 'no' ) ) AS chatPartner, created_at
FROM chatmessages
WHERE receipient = '".$this->id."'
OR sender = '".$this->id."'
HAVING chatPartner != 'no'
ORDER BY created_at DESC
)whateva
GROUP BY whateva.chatPartner
ORDER BY whateva.created_at DESC");
if there is someone out there who can do this query with the Laravel Query Builder, I would be happy to see it. For now I'll leave it like this.

Invalid parameter number error using DataTables with Laravel

When DataTables tries to get data, it always gets tripped up on this Eloquent query:
$items = Item::select([
DB::raw("images.url AS image"),
'items.id',
'items.sku',
'items.quantity',
DB::raw("IF(items.enabled, 'Yes', 'No') AS enabled")
])
->leftJoin('images', function ($j) {
$j->on('images.imageable_id', '=', 'items.id')
->where('images.imageable_type', '=', 'Item');
})
->leftJoin('order_items', 'items.id', '=', 'order_items.item_id')
->leftJoin('orders', 'orders.id', '=', 'order_items.order_id')
->where('items.store_id', 1)
->whereNull('items.deleted_at')
->whereIn('items.status', ['active', 'submitted'])
->groupBy('items.id');
The query works just fine as is and returns the desired results. However, DataTables tries to transform it into the following which produces the error:
select count(*) as aggregate from (select '1' as row from `items` left join `images` on `images`.`imageable_id` = `items`.`id` and `images`.`imageable_type` = 1 left join `order_items` on `items`.`id` = `order_items`.`item_id` left join `orders` on `orders`.`id` = `order_items`.`order_id` where `items`.`store_id` = 1 and `items`.`deleted_at` is null group by `items`.`id`) AS count_row_table
This produces this error specifically:
SQLSTATE[HY093]: Invalid parameter number
/home/vagrant/Projects/test.dev/vendor/laravel/framework/src/Illuminate/Database/Connection.php#301
When I execute that query directly on the MySQL database, it has no problem. This seems to be happening within Laravel only.
If I remove the ->leftJoin('images', function ($j) {...} part of the query then there is no error, but I need that join for the image.
How to get around this error?
Full error output returned to DataTables over AJAX:
{
"error":{
"type":"Illuminate\\Database\\QueryException",
"message":"SQLSTATE[HY093]: Invalid parameter number (SQL: select count(*) as aggregate from (select '1' as row from `items` left join `images` on `images`.`imageable_id` = `items`.`id` and `images`.`imageable_type` = 1 left join `order_items` on `items`.`id` = `order_items`.`item_id` left join `orders` on `orders`.`id` = `order_items`.`order_id` where `items`.`store_id` = active and `items`.`deleted_at` is null and `items`.`status` in (submitted, ?) group by `items`.`id`) AS count_row_table)",
"file":"\/home\/vagrant\/Projects\/test.dev\/vendor\/laravel\/framework\/src\/Illuminate\/Database\/Connection.php",
"line":625
}
}
I have had a similar issue today, not with DataTables but with a complex query being built using the standalone query builder. The issue was similar to yours with the left join, passing a closure to build a more complex join condition. I was using a where condition after the "on".
The solution was to chain "on" calls:
->leftJoin('images', function ($j) {
$j->on('images.imageable_id', '=', 'items.id')
// note the "on" rather than the "where" and the use of a raw statement
->on('images.imageable_type', '=', DB::raw('Item'));
})
I had this exact issue. The work around is not perfect since it will basically grab all the data twice, but it's the only way I could get it to work.
You have to do a ->get(); before sending it to ->make();. I honestly hope someone finds the right solution but for now:
Temp solution:
$data = DB::table('some_table');
$data->leftJoin('some_other_table', function($join)
{
$join->on('some_table.id', '=', 'some_other_table.id')
->where('some_table.something', '=', 'some_value');
});
$data->get();
return Datatables::of($data)->make();
This is with using the datatables package for Laravel: https://github.com/bllim/laravel4-datatables-package