How to convert this MySQL query to Eloquent? - mysql

I am trying to convert a raw SQL query into eloquent and I am struggling with the join part as it gets quite complex.
I have got as far as the joins but I am looking at the documentation and struggling to work out how to convert the rest.
Here is the raw query
SELECT
SUM(CASE WHEN t2.field_2 = 1 THEN 1 ELSE 0 END) AS 'lead',
SUM(CASE WHEN t2.field_2 = 2 THEN 1 ELSE 0 END) AS 'in_review',
SUM(CASE WHEN t2.field_2 = 3 THEN 1 ELSE 0 END) AS 'pre_app_sent',
SUM(CASE WHEN t2.field_2 = 4 THEN 1 ELSE 0 END) AS 'pre_app_back',
SUM(CASE WHEN t2.field_2 = 5 THEN 1 ELSE 0 END) AS 'pre_app_ok',
SUM(CASE WHEN t2.field_2 = 6 THEN 1 ELSE 0 END) AS 'awaiting_kyc',
SUM(CASE WHEN t2.field_2 = 7 THEN 1 ELSE 0 END) AS 'kyc_complete',
SUM(CASE WHEN t2.field_2 = 8 THEN 1 ELSE 0 END) AS 'awaiting_full_app_data',
SUM(CASE WHEN t2.field_2 = 9 THEN 1 ELSE 0 END) AS 'full_app_sent',
SUM(CASE WHEN t2.field_2 = 10 THEN 1 ELSE 0 END) AS 'merchant_live'
FROM leads l
JOIN (SELECT
ae.id,
ae.model_id,
ae.fields,
TRIM(BOTH '"' FROM SUBSTRING_INDEX(SUBSTRING_INDEX(ae.fields,';', 1), ':', -1)) AS field_1,
TRIM(BOTH '"' FROM SUBSTRING_INDEX(SUBSTRING_INDEX(ae.fields,';', 2), ':', -1)) AS field_2,
ae.created_at
FROM action_events ae) t2
ON l.id = t2.model_id
WHERE t2.created_at >= '2019-01-01 00:00:00'
AND t2.created_at <= '2019-01-31 23:59:59'
And here is as far as I got with converting it to eloquent
$query->select(
DB::raw('SUM(CASE WHEN t2.field_2 = 1 THEN 1 ELSE 0 END) AS "lead"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 2 THEN 1 ELSE 0 END) AS "in_review"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 3 THEN 1 ELSE 0 END) AS "pre_app_sent"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 4 THEN 1 ELSE 0 END) AS "pre_app_back"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 5 THEN 1 ELSE 0 END) AS "pre_app_ok"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 6 THEN 1 ELSE 0 END) AS "awaiting_kyc"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 7 THEN 1 ELSE 0 END) AS "kyc_complete"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 8 THEN 1 ELSE 0 END) AS "awaiting_full_app_data"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 9 THEN 1 ELSE 0 END) AS "full_app_sent"'),
DB::raw('SUM(CASE WHEN t2.field_2 = 10 THEN 1 ELSE 0 END) AS "merchant_live"'));

Related

how to write mysql query with join and conditional sum with 3 tables

I have 3 mysql tables which saves invoice, invoice content and payment
inv_head(invno,invtot,invgtot)
inv_body(invno,typeid,qty,rate,linetot)
payment(invno,pay_amount,pay_method)
select inv_head.invno,inv_head.invgtot,
sum(CASE WHEN payment.pay_method='CASH' THEN payment.pay_amount ELSE 0 END) AS pay_cash,
sum(CASE WHEN payment.pay_method='CHEQUE' THEN payment.pay_amount ELSE 0 END) AS pay_chq
from inv_head left JOIN payment on inv_head.invno=payment.invno
where invdate between '2019-07-21 00:00:00' and '2019-07-21 23:00:00'
and unprodid=0
GROUP by inv_head.invno
returns below which is correct
invno invgtot pay_cash pay_chq
20190721-173208-9 242.5 100 100
20190721-174752-9 52 20 10
select inv_head.invno,inv_head.invtot,inv_head.invgtot,
sum(CASE WHEN inv_body.typeid=1 THEN inv_body.line_tot ELSE 0 END) AS stdsaletot,
sum(CASE WHEN inv_body.typeid=2 THEN inv_body.line_tot ELSE 0 END) AS rettot,
sum(CASE WHEN inv_body.typeid=3 THEN inv_body.line_tot ELSE 0 END) AS dmgtot,
sum(CASE WHEN inv_body.typeid=4 THEN (inv_body.qty * inv_body.rate)ELSE 0 END) AS fitot
from inv_head,inv_body
where invdate between '2019-07-21 00:00:00' and '2019-07-21 23:00:00'
and unprodid=0 and inv_head.invno=inv_body.invno
GROUP by inv_head.invno
returns below which is correct
invno invtot invgtot stdsaletot rettot dmgtot fitot
20190721-173208-9 242.5 242.5 242.5 0 0 0
20190721-174752-9 52 52 291 -168 -71 0
but when i combine above 2 queries,
select inv_head.invno,inv_head.invtot,inv_head.invgtot,
sum(CASE WHEN payment.pay_method='CASH' THEN payment.pay_amount ELSE 0 END) AS pay_cash,
sum(CASE WHEN payment.pay_method='CHEQUE' THEN payment.pay_amount ELSE 0 END) AS pay_chq,
sum(CASE WHEN inv_body.typeid=1 THEN inv_body.line_tot ELSE 0 END) AS stdsaletot,
sum(CASE WHEN inv_body.typeid=2 THEN inv_body.line_tot ELSE 0 END) AS rettot,
sum(CASE WHEN inv_body.typeid=3 THEN inv_body.line_tot ELSE 0 END) AS dmgtot,
sum(CASE WHEN inv_body.typeid=4 THEN (inv_body.qty * inv_body.rate)ELSE 0 END) AS fitot
from inv_body,inv_head left JOIN payment on inv_head.invno=payment.invno
where invdate between '2019-07-21 00:00:00' and '2019-07-21 23:00:00'
and unprodid=0 and inv_head.invno=inv_body.invno
GROUP by inv_head.invno
returns below result which is erroneous
invno invtot invgtot pay_cash pay_chq stdsaletot rettot dmgtot fitot
20190721-173208-9 242.5 242.5 100 100 727.5 0 0 0
20190721-174752-9 52 52 80 40 873 -504 -213 0
Your join works properly on payment and inv_head but it is not working on inv_body because you did not provided how to join inv_body with other tables
Try this hope will help you
SELECT inv_head.invno,inv_head.invtot,inv_head.invgtot,
SUM(CASE WHEN payment.pay_method='CASH' THEN payment.pay_amount ELSE 0 END) AS pay_cash,
SUM(CASE WHEN payment.pay_method='CHEQUE' THEN payment.pay_amount ELSE 0 END) AS pay_chq,
SUM(CASE WHEN inv_body.typeid=1 THEN inv_body.line_tot ELSE 0 END) AS stdsaletot,
SUM(CASE WHEN inv_body.typeid=2 THEN inv_body.line_tot ELSE 0 END) AS rettot,
SUM(CASE WHEN inv_body.typeid=3 THEN inv_body.line_tot ELSE 0 END) AS dmgtot,
SUM(CASE WHEN inv_body.typeid=4 THEN (inv_body.qty * inv_body.rate)ELSE 0 END) AS fitot
FROM payment RIGHT JOIN inv_head ON inv_head.invno=payment.invno
WHERE invdate BETWEEN '2019-07-21 00:00:00' AND '2019-07-21 23:00:00'
AND unprodid=0 LEFT JOIN inv_body ON inv_head.invno=inv_body.invno
GROUP BY inv_head.invno

Is there a way to sum values of the row?

I have a SQL QUERY, where im using SUM:
SELECT
SUM(CASE WHEN `ID_Event1` != 0 THEN 1 ELSE 0 END) AS count1,
SUM(CASE WHEN `ID_Event2` != 0 THEN 1 ELSE 0 END) AS count2,
SUM(CASE WHEN `ID_Event3` != 0 THEN 1 ELSE 0 END) AS count3,
SUM(CASE WHEN `ID_Event4` != 0 THEN 1 ELSE 0 END) AS count4,
SUM(CASE WHEN `ID_Event5` != 0 THEN 1 ELSE 0 END) AS count5
FROM `ec_calendar` WHERE Year(`Day`)=2015 AND Month(`Day`)=6
The result is:
But i want SUM these colums. Expected result is 17 (3+4+3+3+4).
Is there any solution?
Then use +:
SELECT (SUM(CASE WHEN `ID_Event1` != 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN `ID_Event2` != 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN `ID_Event3` != 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN `ID_Event4` != 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN `ID_Event5` != 0 THEN 1 ELSE 0 END)
) as cnt
FROM `ec_calendar`
WHERE day >= '2015-06-01' and day < '2015-07-01'
Note that I changed the WHERE clause. This method is more efficient if you have index on day.
MySQL treats booleans as integers, so you can write this as:
SELECT (SUM(ID_Event1 <> 0) + SUM(ID_Event2 <> 0) +
SUM(ID_Event3 <> 0) + SUM(ID_Event4 <> 0) +
SUM(ID_Event5 <> 0)
) as cnt
FROM `ec_calendar`
WHERE day >= '2015-06-01' and day < '2015-07-01'
You can just add the calculated columns.
SELECT
SUM(CASE WHEN `ID_Event1` != 0 THEN 1 ELSE 0 END) AS count1,
SUM(CASE WHEN `ID_Event2` != 0 THEN 1 ELSE 0 END) AS count2,
SUM(CASE WHEN `ID_Event3` != 0 THEN 1 ELSE 0 END) AS count3,
SUM(CASE WHEN `ID_Event4` != 0 THEN 1 ELSE 0 END) AS count4,
SUM(CASE WHEN `ID_Event5` != 0 THEN 1 ELSE 0 END) AS count5,
SUM(CASE WHEN `ID_Event1` != 0 THEN 1 ELSE 0 END)+
SUM(CASE WHEN `ID_Event2` != 0 THEN 1 ELSE 0 END)+
SUM(CASE WHEN `ID_Event3` != 0 THEN 1 ELSE 0 END)+
SUM(CASE WHEN `ID_Event4` != 0 THEN 1 ELSE 0 END)+
SUM(CASE WHEN `ID_Event5` != 0 THEN 1 ELSE 0 END) as total
FROM `ec_calendar` WHERE Year(`Day`)=2015 AND Month(`Day`)=6

Calculate date difference in sql for specific year

I have two dates, say start_date is 20141215 and end_date = 20150115. I would like to use SQL DATEDIFF to only count the dates within the year 2015 which I will specify in the query. Here is the current SQL I have written:
SELECT COUNT(leave_id),
sum(case when leave_status = 1 then 1 else 0 end) pending,
sum(case when leave_status = 2 then 1 else 0 end) declined,
sum(case when leave_status = 3 then 1 else 0 end) approved,
sum(case when leave_status = 4 then 1 else 0 end) rostered,
SUM(DATEDIFF(end_date, start_date)+1) as datetotals
FROM employee_leave WHERE
((YEAR(start_date) = :year) OR (YEAR(end_date) = :year))
AND employee_id = :emp_id
Thanks
You need to fix datediff() to only consider dates during the year. I think this does what you want:
SELECT COUNT(leave_id),
sum(case when leave_status = 1 then 1 else 0 end) pending,
sum(case when leave_status = 2 then 1 else 0 end) declined,
sum(case when leave_status = 3 then 1 else 0 end) approved,
sum(case when leave_status = 4 then 1 else 0 end) rostered,
SUM(DATEDIFF(least(end_date, date(concat_ws('-', :year, 12, 31))),
greatest(start_date, date(concat_ws('-', :year, 1, 1)))
) + 1) as datetotals
FROM employee_leave
WHERE ((YEAR(start_date) = :year) OR (YEAR(end_date) = :year)) AND
employee_id = :emp_id
Make it a AND condition rather like
WHERE
((YEAR(start_date) = :year) AND (YEAR(end_date) = :year))

How could I check the value of an aggregation function inside the same query?

This MySQL query gives me this error 'Unknown column 'winnings' in 'field list'
SELECT
o.user_id,
sum(case when o.result = 1 or o.result=2 or o.result = 0 then 1 else 0 end) as tahmins_no,
sum(case when o.result = 1 then 1 else 0 end) as winnings,
sum(case when o.result = 2 then 1 else 0 end) as loses,
sum(case when winnings = 10 then 0.5 else 0 end) as counter
FROM `odds_tahminler` o
I know that winnings is the value of the sum() aggregation function, But is there any way to check the winnings value within the query?
You can't use an aggregated column inside the select. However you can use a subquery to obtain the counter value after all the aggregated columns have been computed.
How is the counter value calculated? I assumed that the counter should be (winnings - 10) / 2 if there's at least 10 winnings and 0 otherwise. In that case you can obtain it with this query
SELECT O.*,
GREATEST( (O.winnings - 10) / 2, 0) as counter
FROM
(
SELECT u.username,
o.user_id,
sum(case when o.result = 1 or o.result=2 or o.result = 0 then 1 else 0 end) as tahmins_no,
sum(case when o.result = 1 then 1 else 0 end) as winnings,
sum(case when o.result = 2 then 1 else 0 end) as loses
FROM `odds_tahminler` o
) as O
you can try:
SELECT
o.user_id,
sum(case when o.result = 1 or o.result=2 or o.result = 0 then 1 else 0 end) as tahmins_no,
sum(case when o.result = 1 then 1 else 0 end) as winnings,
sum(case when o.result = 2 then 1 else 0 end) as loses,
sum(case when winnings = 10 then 0.5 else 0 end) as counter
FROM `odds_tahminler` o
GROUP BY o.user_id
HAVING counter>2

mySQL query comparing rows and columns

I have a database of user answers from a quiz which contains 8 questions. Q1 - Q8 all are their own columns, I'd like to compare all the rows and get a number back for everyone who answered the same for at least 5 questions.
so here, rows 5 and 6 would count as 2. Basically I'm trying to get a number for everyone who answered at least 5 questions the same. Is this possible with a mySQL query?
EDIT:
Here the user enters D B D A B C D B, matching with 2 similarly answered quizzes. The query here would return a count of 2.
If we test using just your single line of D B D A B C D B we can use the following example:
SELECT * FROM `answers` WHERE ((CASE WHEN q1 = 'D' THEN 1 ELSE 0 END) +
(CASE WHEN q2 = 'B' THEN 1 ELSE 0 END) +
(CASE WHEN q3 = 'D' THEN 1 ELSE 0 END) +
(CASE WHEN q4 = 'A' THEN 1 ELSE 0 END) +
(CASE WHEN q5 = 'B' THEN 1 ELSE 0 END) +
(CASE WHEN q6 = 'C' THEN 1 ELSE 0 END) +
(CASE WHEN q7 = 'D' THEN 1 ELSE 0 END) +
(CASE WHEN q8 = 'B' THEN 1 ELSE 0 END)) >= 5;
However, if we then want to go a step further and test each answer against the other answers in the table we can use the following statement:
SELECT *, (SELECT COUNT(answer_sub.idanswers) FROM `answers` answer_sub
WHERE ((CASE WHEN answer_sub.q1 = a.q1 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q2 = a.q2 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q3 = a.q3 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q4 = a.q4 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q5 = a.q5 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q6 = a.q6 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q7 = a.q7 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q8 = a.q8 THEN 1 ELSE 0 END)) >= 5
AND answer_sub.idanswers <> a.idanswers) as matching
FROM `answers` a
WHERE (SELECT COUNT(answer_sub.idanswers) FROM `answers` answer_sub
WHERE ((CASE WHEN answer_sub.q1 = a.q1 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q2 = a.q2 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q3 = a.q3 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q4 = a.q4 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q5 = a.q5 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q6 = a.q6 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q7 = a.q7 THEN 1 ELSE 0 END) +
(CASE WHEN answer_sub.q8 = a.q8 THEN 1 ELSE 0 END)) >= 5
AND answer_sub.idanswers <> a.idanswers) > 0
Because FALSE is 0 and TRUE is 1 in MySQL:
SELECT COUNT(*)
FROM quiz
WHERE ( (q1=#q1) + (q2=#q2) + (q3=#q3) + (q4=#q4)
+ (q5=#q5) + (q6=#q6) + (q7=#q7) + (q8=#q8)
) >= 5