I'm having difficulty converting a SQL to the eloquent of laravel, specifically in the part of an inner join, where I make the comparison in a "in" different of the "="
Query:
SELECT
titulo_id as titulo_id,
-- calculate both SUMs, select values for each dependent by what value it matches to
SUM(CASE WHEN ativos_extratos.data_import_id = borders.min_id THEN valor_bruto_atual END) AS valor_min,
SUM(CASE WHEN ativos_extratos.data_import_id = borders.max_id THEN valor_bruto_atual END) AS valor_max,
data_imports.data_import AS created_at,
week(data_imports.data_import) AS weeknumber
FROM
ativos_extratos
INNER JOIN
titulos ON titulo_id = titulos.id
INNER JOIN
representantes ON representante_id = representantes.id
INNER JOIN
data_imports ON data_import_id = data_imports.id
INNER JOIN ( SELECT
MIN(ID) as min_id,
MAX(ID) as max_id
FROM
data_imports
WHERE
data_import BETWEEN '2018-11-01' AND '2018-12-10'
GROUP BY week(data_import)
) borders ON ativos_extratos.data_import_id IN (borders.min_id, borders.max_id)
WHERE
user_id = 1
AND data_imports.data_import BETWEEN '2018-11-01' AND '2018-12-10'
GROUP BY titulos.nome_titulo , weeknumber
Current Eloquent ORM
$rows = AtivosExtrato::select('titulo_id',
DB::raw('SUM(CASE WHEN ativos_extratos.data_import_id = borders.min_id THEN valor_bruto_atual END) AS valor_init'),
DB::raw('SUM(CASE WHEN ativos_extratos.data_import_id = borders.max_id THEN valor_bruto_atual END) AS valor_end'),
'data_imports.data_import AS created_at',
DB::raw('month(data_imports.data_import) AS weeknumber')
)
->join('titulos','titulo_id', '=', 'titulos.id' )
->join('representantes','representante_id', '=', 'representantes.id' )
->join('data_imports','data_import_id', '=', 'data_imports.id' )
->join(DB::raw("
( SELECT
MIN(ID) as min_id,
MAX(ID) as max_id
FROM
data_imports
WHERE
data_import BETWEEN '2018-10-01' AND '2018-12-10'
GROUP BY month(data_import)) borders
"), function ($join){
$join->on('ativos_extratos.data_import_id', 'in', "(borders.min_id, borders.max_id')");
})
->where('user_id', Auth::user()->id)
->whereBetween('data_import', ['2018-01-01', '2018-12-10'])
->groupBy('titulos.nome_titulo')
->groupBy('weeknumber')
->orderBy('data_import')
->orderBy('titulos.nome_titulo')
->get();
The problem is at the time I do the join using the "in", but it does not run as it should, it concatenates "=" and other fields.
You can try to use whereIn,
Here is an example :
$users = DB::table('users')
->whereIn('id', array(1, 2, 3))->get();
Try something like :
$join->whereIn('ativos_extratos.data_import_id', '(borders.min_id, borders.max_id)');
instead of $join->on('ativos_extratos.data_import_id', 'in', "(borders.min_id, borders.max_id')");
More documentation: https://laravel.com/docs/5.0/queries and
https://github.com/illuminate/database/blob/master/Query/Builder.php#L824
Related
I am new to Laravel and trying to support an existing application that is in Laravel 5. I am trying to convert the following SQL to eloquent structure
SELECT s.id,
CONCAT(u.first_name, ' ', u.last_name) AS user_name,
u.avatar_location AS user_img,
s.employee_photo,
d.name AS department,
seg.name AS segment,
s.survey_title,
s.before_action,
s.before_picture,
s.action,
s.action_date,
s.after_action,
s.after_picture,
s.nominated,
s.awarded,
s.created_at,
s.updated_at,
(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id) AS likes,
(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id AND l.user_id = 5) AS UserLikes,
(SELECT COUNT(1) FROM comments c WHERE c.survey_id = s.id ) AS comments
FROM surveys s
JOIN departments d
ON s.department = d.id
JOIN segments seg
ON s.segment_id = seg.id
JOIN users u
ON s.user_id = u.id
WHERE s.status = 'Approved'
ORDER BY s.action_date DESC
LIMIT 20 OFFSET 20
I know enough Laravel to know that my basic start would probably be
$surveys = DB::table('surveys')
->join('departments', 'surveys.department', '=', 'departments.id')
->join('segments', 'surveys.segment_id', '=', 'segments.id')
->join('users', 'surveys.user_id', '=', 'users.id')
->where('surveys.status', 'Approved')
->orderBy('surveys.action_date')
->skip(20)-take(20)
->select(...)->get();
However, I am not sure how to do the subqueries. Looking for any suggestions.
Thanks!
For select statements, you can use DB::raw().
$surveys = DB::table('surveys')
->join('departments', 'surveys.department', '=', 'departments.id')
->join('segments', 'surveys.segment_id', '=', 'segments.id')
->join('users', 'surveys.user_id', '=', 'users.id')
->where('surveys.status', 'Approved')
->orderBy('surveys.action_date')
->skip(20)-take(20)
->select([DB::raw('(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id) AS likes'),
...
])
->get();
Similarly, select statements would go under the select array. Just so to be clear, the result will be a collection.
I want to convert this Mysql code to Laravel Eloquent
select service_id, sum(cnt) from
(
select * from
(
select service_id, count(*) cnt from prdouct_notifs
join products on products.id = prdouct_notifs.product_id
where prdouct_notifs.user_id = 268
and prdouct_notifs.deleted_at is null
and prdouct_notifs.block = 4
group by service_id
) first_table
union All
(
select service_id, count(*) cnt from products
where products.pro_user_id = 268
and products.status = 47575
group by service_id
)
) total_union group by service_id
I changed this code to Laravel Eloquent.
$get_product = Product::where('pro_user_id', 268)
->where('status', 47575)
->groupby('service_id')
->selectRaw('service_id ,count(*) cnt');
$get_final_product = prdouct_notifs::join('products', function ($join){
$join->on('products.id', '=', 'prdouct_notifs.product_id')
->where('prdouct_notifs.user_id', 268)
->where('prdouct_notifs.block', 4);
})
->selectRaw('service_id ,count(*) cnt')
->groupby('service_id')
->unionAll($get_product)
->get();
the question is how to run groupby after unionAll
That's what I want to changed into eloquent.
total_union group by service_id
My idea is to put the UNION into a sub query before grouping. I hope this answers to your question.
$product = DB::table('products as p')
->where('p.status', 47575)
->select('p.service_id as service_id');
$productNotify= DB::table('prdouct_notifs as pn')
->select('pn.service_id as service_id')
->union($product);
$groupby = DB::query()->fromSub($productNotify, 'p_pn')
->select('service_id', DB::raw('COUNT(*) as cnt'))
->groupBy('service_id');
Which produce the following SQL
select "stud_id", COUNT(*) as total_asset from (
select * from (select p.service_id as service_id from products as p)
union
select * from (select pn.service_id as service_id from prdouct_notifs as pn)
) as p_pn
group by service_id
I have the following SQL
SELECT C.CUOCODE, C.NAME, COUNT(*) TOTAL_PAYMENT, SUM(P.AMOUNT) TOTAL_AMOUNT
FROM TAX_PAYMENT P
INNER JOIN TAX_CHECKPOINT C ON C.CUOCODE = REGEXP_SUBSTR(P.INVOICEID, 'R....')
WHERE DELETED = 0 AND TO_CHAR(TXTIME,'YYYY-MM-DD') = '2018-04-24'
GROUP BY C.CUOCODE, C.NAME
ORDER BY TOTAL_AMOUNT DESC;
How can i convert to laravel eloquent, i have "Payment" model (table TAX_PAYMENT) with "paymentid" as primary key.
DB::table('TAX_PAYMENT as P')
->select([
'C.CUOCODE',
'C.NAME',
DB::raw('COUNT(*) AS TOTAL_PAYMENT'),
DB::raw('SUM(P.AMOUNT) AS TOTAL_AMOUNT'),
])->Join('TAX_CHECKPOINT C', 'C.CUOCODE', '=', DB::raw('REGEXP_SUBSTR(P.INVOICEID,'R....')'))
->where('DELETED', 0)
->where(DB::raw("TO_CHAR(TXTIME,'YYYY-MM-DD')"), '2018-04-24')
->groupBy('C.CUOCODE')
->groupBy('C.NAME')
->orderBy('TOTAL_AMOUNT', 'desc')
->toSql();
output
SELECT
`C`.`CUOCODE`,
`C`.`NAME`,
COUNT(*) AS TOTAL_PAYMENT,
SUM(P.AMOUNT) AS TOTAL_AMOUNT
FROM
`TAX_PAYMENT` AS `P`
INNER JOIN `TAX_CHECKPOINT C` ON `C`.`CUOCODE` = REGEXP_SUBSTR (P.INVOICEID,"R....")
WHERE
`DELETED` = ?
AND TO_CHAR (TXTIME, 'YYYY-MM-DD') = ?
GROUP BY
`C`.`CUOCODE`,
`C`.`NAME`
ORDER BY
`TOTAL_AMOUNT` DESC
A quick and dirty way would be to use Eloquents select raw like:
$result = DB::select( DB::raw("SELECT C.CUOCODE, C.NAME, COUNT(*)
TOTAL_PAYMENT, SUM(P.AMOUNT) TOTAL_AMOUNT FROM TAX_PAYMENT INNER JOIN
TAX_CHECKPOINT C ON C.CUOCODE
= REGEXP_SUBSTR(P.INVOICEID, 'R....') WHERE DELETED = 0 AND
TO_CHAR(TXTIME,'YYYY-MM-DD') = '2018-04-24' GROUP BY C.CUOCODE,
C.NAME ORDER BY TOTAL_AMOUNT DESC"));
I have 3 tables: Users, Properties, Units
User table:
user_id user_name
Properties table
pty_id pty_name user pty_status
Units Table
unit_id unit_name pty_id unit_status
i want to show user details , number of properties and units and their details.
Here is my query:
DB::statement('SET SESSION group_concat_max_len = 10485760');
$ar = DB::table('users as u')
->leftjoin('properties as p', function($join) {
$join->on('p.user_id', '=', 'u.user_id')->where('p.pty_status', '!=' ,0 );
})
->leftJoin(
DB::raw("
(select COALESCE(count(unit_id),0) AS cntunits, pty_id as temp_pty
from property_units as pu3
left join properties as p2 on pu3.unit_pty_id = p2.pty_id
where pu3.unit_status!=0
group by p2.pty_id) as temp"), 'p.pty_id', '=', 'temp.temp_pty')
->select(
DB::raw("group_concat(DISTINCT CONCAT(ej_p.pty_id,'|',ej_p.pty_name,'|',cntunits)) as pty_details"),
DB::raw("group_concat(DISTINCT CONCAT(ej_p.pty_id,'|',ej_p.pty_name)) as pty_details_copy")
)->paginate(10);
When I group_concat the unit_count, only those properties and units are concated where unit exists.
For example the above query returns the following result:
pty_details pty_details_copy
7|I2|2 7|I2, 22|tR ,51|SG APARTMENT,54_||_GA APARTMENTS,
Why properties with units (where unit count=0) are not binding? Where have I gone wrong?
EDIT
Here is the raw query:
select group_concat(DISTINCT CONCAT(p.pty_id,'|',p.pty_name,'|',cntunits)) as pty_details,
group_concat(DISTINCT CONCAT(p.pty_id,'|',p.pty_name)) as pty_details_copy
from users as u
left join properties as p on p.user_id = u.user_id and p.pty_status !=0
left join
(select COALESCE(count(unit_id),0) AS cntunits, pty_id as temp_pty
from property_units as pu3
left join properties as p2 on pu3.unit_pty_id = p2.pty_id
where pu3.unit_status!=0
group by p2.pty_id) as temp on p.pty_id = temp.temp_pty
As Solarflare suggested, i got the required result when I changed the query like this:
$ar = DB::table('users as u')
->leftjoin('properties as p', function($join) {
$join->on('p.user_id', '=', 'u.user_id')->where('p.pty_status', '!=' ,0 );
})
->leftJoin(
DB::raw("
(select COALESCE(count(unit_id),0) AS cntunits, pty_id as temp_pty
from property_units as pu3
left join properties as p2 on pu3.unit_pty_id = p2.pty_id
where pu3.unit_status!=0
group by p2.pty_id) as temp"), 'p.pty_id', '=', 'temp.temp_pty')
->select(
DB::raw("group_concat(DISTINCT CONCAT(ej_p.pty_id,'|',ej_p.pty_name,'|',coalesce(cntunits, 0))) as pty_details"))->paginate(10);
The WHERE from your first join should be part of the ON.
I have the following query and it's doing it's job fine:
SELECT exams.id, exams.date FROM exams
WHERE exams.modul_id = (SELECT questions.modul_id FROM questions where questions.id = 5)
AND NOT EXISTS (
SELECT * FROM exam_question, questions
WHERE questions.id = 5
AND questions.id = exam_question.question_id
AND exam_question.exam_id = exams.id
)
It returns me all exams that belong to the same model as exam but not connteced to exam yet.
I want to use this query in Laravel but I always get an empty result back (it shouldn't be empty)
DB::table('exams')
->select(['id', 'date'])
->whereRaw('modul_id = '.$question->modul_id)
->whereNotExists(function ($query) use ($question) {
$query->select(DB::raw(1))
->from('questions as q')
->join('exam_question as eq', 'q.id', '=', 'eq.question_id')
->join('exams as e', 'eq.exam_id', '=', 'e.id')
->whereRaw('q.id = '.$question->id);
})
->get();
The output of the laravel expression is:
select `id`, `date` from `exams` where modul_id = 1 and not exists (select 1 from `questions` as `q` inner join `exam_question` as `eq` on `q`.`id` = `eq`.`question_id` inner join `exams` as `e` on `eq`.`exam_id` = `e`.`id` where q.id = 5)
I see problem in your sql query dump in section and not exists (... you select starts with select 1 from it will always select number 1 from your table according to selected rows count
select `id`, `date` from `exams`
where modul_id = 1
and not exists (
select 1 from `questions` as `q`
inner join `exam_question` as `eq` on `q`.`id` = `eq`.`question_id`
inner join `exams` as `e` on `eq`.`exam_id` = `e`.`id` where q.id = 5)
You have to use in query builder instead $query->select(DB::raw(1)) ... -> $query->select('*') ...
DB::table('exams')
->select(['id', 'date'])
->whereRaw('modul_id = '.$question->modul_id)
->whereNotExists(function ($query) use ($question) {
$query->select('*')
->from('questions as q')
->join('exam_question as eq', 'q.id', '=', 'eq.question_id')
->join('exams as e', 'eq.exam_id', '=', 'e.id')
->whereRaw('q.id = '.$question->id);
})
->get();
If the rest logic which you used to create your query is correct it will start to work