Convert Mysql Query to Laravel Eloquent - mysql

I am using Laravel 5.1 in my application.
My MySQL Query is
SELECT * FROM (SELECT uu.*,t.left_id AS meb_id,(CAST(t.pair AS UNSIGNED) - IFNULL(p.pair,0)) AS pair FROM (SELECT left_id,
(CASE
WHEN ((SELECT COUNT(meb_id) FROM user_count WHERE left_id=u.left_id AND active = 1 AND join_date <= '1442255400000') >= (SELECT COUNT(meb_id) FROM user_count WHERE right_id=u.left_id AND active = 1 AND join_date <= '1442255400000')*2)
THEN (SELECT COUNT(meb_id) FROM user_count WHERE right_id=u.left_id AND active = 1 AND join_date <= '1442255400000')
WHEN ((SELECT COUNT(meb_id) FROM user_count WHERE left_id=u.left_id AND active = 1 AND join_date <= '1442255400000') < (SELECT COUNT(meb_id) FROM user_count WHERE right_id=u.left_id AND active = 1 AND join_date <= '1442255400000')*2)
THEN ((SELECT COUNT(meb_id) FROM user_count WHERE right_id=u.left_id AND active = 1 AND join_date <= '1442255400000') /2)
WHEN ((SELECT COUNT(meb_id) FROM user_count WHERE right_id=u.left_id AND active = 1 AND join_date <= '1442255400000') >= (SELECT COUNT(meb_id) FROM user_count WHERE left_id=u.left_id AND active = 1 AND join_date <= '1442255400000')*2)
THEN (SELECT COUNT(meb_id) FROM user_count WHERE left_id=u.left_id AND active = 1 AND join_date <= '1442255400000')
WHEN ((SELECT COUNT(meb_id) FROM user_count WHERE right_id=u.left_id AND active = 1 AND join_date <= '1442255400000') < (SELECT COUNT(meb_id) FROM user_count WHERE left_id=u.left_id AND active = 1 AND join_date <= '1442255400000')*2)
THEN ((SELECT COUNT(meb_id) FROM user_count WHERE left_id=u.left_id AND active = 1 AND join_date <= '1442255400000') / 2) END
) AS pair
FROM user_count AS u WHERE left_id <> 0 GROUP BY left_id) AS t
LEFT JOIN users AS uu ON uu.`id` = t.left_id
LEFT JOIN `total_payment` p ON t.left_id = p.`meb_id`
WHERE t.pair <> 0) AS f WHERE f.pair > 0 AND f.active = 1
How Can I convert it in Laravel Eloquent? I don't know how to use when case in laravel eloquent.
My Database schema is like this
user_count table
user table
total_payment table
Can anyone help me please?

Just surround your raw query with a DB::statement(""), like this :
DB::statement("INSERT INTO `mydatabase`.`mytable` (`id`, `created_at`, `updated_at`, `deleted_at`) VALUES ('7', '2015-09-26 13:38:48', '2015-09-26 13:43:41', NULL)");
It will do the job fine and works with seeds as well.

Eloquent is an ORM (Object-relational mapping), it means you can map your database to PHP objects (Eloquent use the Active Record pattern).
It is not a DBAL however you can still execute SQL queries through the DB Facade.
The example provided by you, the user table can be an Eloquent object.
class User extends Model{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'user';
}
Since now you can fetch all user rows like:
$userCollection = (new User)->all(); //Fetch all rows
Or you can find one by PK like:
$user = (new User)->find(123); //123 is the PK of the User

Related

Get recent count from a column

I would like to get the count of a column based on its recent status.
Please see table structure below:
id | visible | date
1 | 1 | 2021-07-22
2 | 1 | 2021-07-23
3 | 0 | 2021-07-24
4 | 1 | 2021-07-25
5 | 0 | 2021-07-26
6 | 0 | 2021-07-27
For example, if I query
SELECT COUNT(visible) AS latest_not_visible WHERE date = '2021-07-26'
then it should return
latest_not_visible
1
Since it only counts that date as not visible, it disregarded the count on 07/24 since 07/25 is visible
But if I query
SELECT COUNT(visible) AS latest_not_visible WHERE date = '2021-07-27'
latest_not_visible
2
since 07/26 and 07/27 are both non-visible and no date in between is visible
I already had the solution to the problem, but I would need help in optimizing this function:
IIF(datediff
(day,
(SELECT MAX(date) FROM t1 WHERE (visible = 0 OR visible = '-1' OR visible = '-3') AND item_id = vp.item_id AND [date] <= vp.date),
(SELECT MAX(date) FROM t1 WHERE visible = 1 AND item_id = vp.item_id AND [date] <= vp.date)) IS NULL
OR datediff(day,
(SELECT MAX(date) FROM t1 WHERE (visible = 0 OR visible = '-1' OR visible = '-3') AND item_id = vp.item_id AND [date] <= vp.date),
(SELECT MAX(date) FROM t1 WHERE visible = 1 AND item_id = vp.item_id AND [date] <= vp.date)) < 0,
(SELECT COUNT(1) FROM t1 WHERE (visible = 0 OR visible = '-1' OR visible = '-3') AND item_id = vp.item_id AND [date] <= vp.date), 0)
AS times_not_visible,
table vp is the original table same with t1
Rather than counting them, you're better to calculate the number of days between the last visible and not visible on or before that date. So something like this...
SELECT DATEDIFF(
SELECT MAX(date) FROM YourTable WHERE visible = 0 AND date <= '2021-07-27'),
SELECT MAX(date) FROM YourTable WHERE visible = 1 AND date <= '2021-07-27')
) as latest_not_visible;
Find the latest visible date earlier than the given date and count all rows in between those two dates:
SET #dt = '2021-07-25';
SELECT COUNT(*)
FROM t
WHERE date <= (SELECT date FROM t WHERE date = #dt AND visible = 0)
AND date > (SELECT date FROM t WHERE date < #dt AND visible = 1 ORDER BY date DESC LIMIT 1)
SQL Fiddle
A solution with GROUP_CONCAT():
SELECT CHAR_LENGTH(visible) - CHAR_LENGTH(TRIM(TRAILING '0' FROM visible)) latest_not_visible
FROM (
SELECT GROUP_CONCAT(visible ORDER BY date SEPARATOR '') visible
FROM tablename
WHERE date <= ?
) t
Change ? to the date you want.
See the demo.
You can use window functions:
select count(*)
from (select t.*,
max(case when visible = 1 then date end) over (order by date) as max_visible_date
from t
where date <= '2021-07-26' -- or whatever
) t
where visible = 0 and
(date > max_visible_date or max_visible_date is null);
Note that this version only mentions the date once. It also works for if there are no rows with visible = 1, and it works on any number of rows.

MySQL query is not coming back - performance enhancements?

I have a shopware database which has the structure:
s_articles: all products
id | name | mode
s_order: all orders
id | ordertime | userId | status
s_order_details: all line items for an order
id | orderId | articleId
Now I want to achieve the following: I want to now how many users bought a product in the last 90 days which have bought the same product also earlier than the last 90 days.
I do it like this: I get all articles, then I get count all customers who have bought the article before the last 90 days "boughtBefore90", then I have another sub-select with another sub-select where I collect all the users who have bought the product in the last 90 days and have bought it earlier than that as well and save it in "boughtLast90".
Then I calcucate the retention rate. This works well with one product, but not with the whole articles database. Is there any way to write this sql with better performance in mind?
My query looks like this:
select articleId, articleName, boughtBefore90, boughtLast90, boughtLast90/boughtBefore90 as 'retention'
FROM
(select
s_articles.id as 'articleId',
s_articles.name as 'articleName',
(select count(*)
FROM s_order_details as s_order_details_2
join s_order as s_order_2 on s_order_2.Id = s_order_details_2.orderId
where s_order_details_2.articleId = s_articles.id
and (s_order_2.status = 0 or s_order_2.status = 2)
and s_order_2.ordertime > '2017-01-01 00:00:00'
and s_order_2.ordertime < '2017-03-09 23:59:59'
) as 'boughtBefore90',
(select count(*) from s_order_details as s_order_details_3
join s_order as s_order_3 on s_order_3.id = s_order_details_3.orderId
where s_order_3.ordertime > '2017-03-10 00:00:00'
and s_order_3.ordertime < '2017-06-07 23:59:59'
and s_order_details_3.articleId = s_articles.id
and (s_order_3.status = 0 or s_order_3.status = 2)
AND s_order_3.userId = (
select DISTINCT(s_order_4.userId) from s_order_details as s_order_details_4
join s_order as s_order_4 on s_order_4.id = s_order_details_4.orderId
where s_order_4.ordertime > '2017-01-01 00:00:00'
and s_order_4.ordertime < '2017-03-09 23:59:59'
and s_order_details_4.articleId = s_articles.id
and s_order_3.userId = s_order_4.userId
and (s_order_4.status = 0 or s_order_4.status = 2))
) as 'boughtLast90'
from
s_articles
join s_order_details on s_order_details.articleID = s_articles.id
join s_order on s_order.id = s_order_details.orderId
WHERE s_articles.mode = 0
AND s_order_details.modus = 0
AND (s_order.status = 2 or s_order.status = 0)
group by s_articles.id) as resulttable;
Thank you!
This seems like a pretty simple query. Here is the list of customers and articles:
select o.customerid, od.articleid
from s_orders o join
s_order_details od
on od.orderid = o.id
group by o.customerid, od.articleid
having max(o.ordertime) > curdate() - interval 90 days and
min(o.ordertime) <= curdate() - interval 90 days;
If you want a count, use this as a subquery and use either count(*) (for customer/article pairs) or count(distinct customerid) (for the number of customers).

SQL JOIN COUNT then using that count value in where clause

I'm trying to select if a user rating (user.rating) is greater then 6 or if the user has more then 100 transactions (transaction table count). Basically count how many transactions the user has then where (transaction count >= 100 OR user rating >= 6).
SELECT *
FROM `user`
JOIN (SELECT COUNT(*)
FROM transaction
WHERE transaction.user_id=user.id
AND type='L'
AND status='S') AS tcount
WHERE (user.rating >= '6' OR tcount >= '100')
Just another possible answer. I've created simplified schemas to test it, please try it and let me know the result.
SELECT *
FROM user
WHERE user.rating >= 6 OR (SELECT COUNT(*) FROM transaction WHERE user_id = user.id and type = 'L' and status = 'S') >= 100;
Use an alias on COUNT(*)
SELECT *
FROM `user`
JOIN (SELECT user_id, COUNT(*) cnt
FROM transaction
WHERE type='L'
AND status='S'
GROUP BY user_id) AS tcount
ON user.id = tcount.user_id
WHERE (user.rating >= '6' OR tcount.cnt >= '100')
You can write that without the subquery, like this
SELECT u.id
FROM `user` u
JOIN `transaction` t
ON t.user_id=u.id
WHERE t.type = 'L' AND t.status = 'S'
GROUP BY u.id
HAVING sum(case when u.rating >= 6 then 1 end) > 0 OR count(*) >= 100

Multiple not exists in MYSQL to check count of rows

I am trying to make this query work, here is my logic , I am trying to select record thats there is not at LEAST NOT one of these options:
1). status = Approved AND end_date >now
2). status =Approved AND end_date is NULL
3). status = Pending And end_date is NULL & COUNT(id) =1
4). status =Pending AND end_date >now & COUNT(id) =1
5). status =Pending AND end_date <now & COUNT(id) =1
how to accomplish this , this is what I have so far I am not sure how to check for COUNT(id) = 1 in conditions 3, 4, and 5?
SELECT
*
FROM
outreach
WHERE
NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Approved"
AND end_date > now()
)
AND NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Approved"
AND end_date IS NULL
)
AND NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Pending"
AND end_date > now()
)
AND NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Pending"
AND end_date IS NULL
)
AND NOT EXISTS (
SELECT
*
FROM
outreach_links
WHERE
outreach_links.outreach_id = outreach.id
AND STATUS = "Pending"
AND end_date < now()
)
select
o.*,
SUM(if(ol.status = "Approved" and (ol.end_date > now() or end_date is null), 1, 0)) as cond1,
SUM(if(ol.status = "Pending" and (ol.end_date != now() or end_date is null), 1, 0)) as cond2
from
outreach o
left join
outreach_links ol on ol.outreach_id = o.id
group by
o.id
having
cond1 = 0 and cond2 != 1
;
Not sure if that's you are looking for, but you can try it.
cond2 != 1 makes your COUNT(id) = 1 condition (if there are more than one linked id in outreach_links cond2 will be greater than 1)

fetch no of rows from table 2 with id of table 1

I have some thing to do here with subquery but I am not able to do.
I want the result from a table with a extra field to show to no of results from other table with a column value from table 1.
table1:
CountryId Country ISO2 ISO3
table2:
id noof_country state
I have to retrive noof_country count in table 1 as count field
EDIT
my actual tables are
table 1:
ad_id job_country status delete days_left
table 2:
CountryId Country ISO2 status
I have done query in two phase:
$sql_map = "select distinct c.ISO2, c.Country, a.job_country
from rec_countries c, rec_advert a
where c.status = 1
and DATE(a.modified_date) >= CURDATE() - INTERVAL 30 DAY
and c.ISO2 <> '--'
and c.ISO2 <> ''
and c.CountryId = a.job_country
and a.status = 1
and a.`delete` = 0
and a.days_left >0
";
$res = mysql_query($sql_map);
while($row = mysql_fetch_array($res)){
$jobs_no = count($row['job_country']);
$sql_job = "SELECT COUNT( job_country ) AS jobs_no
FROM rec_advert
WHERE job_country = ".$row['job_country']."
and status = 1
and `delete` = 0
and days_left >0";
$resjob=mysql_query($sql_job);
$rowjob = mysql_fetch_array($resjob);
//here jobs_no is the count of total rows
}
Here I want to do with subquery.
If I read the question right, this should work:
SELECT
CountryId,
Country,
ISO2,
ISO3,
(
SELECT COUNT(DISTINCT noof_country)
FROM table2
WHERE table2.id = table1.CountryId
) AS noof_country_count
FROM table1
It's not immediately clear in your question which column in table1 is a foreign key to which column in table2... or if they are even related that way. If this query doesn't work for you, please clarify your schema.
Based on your updated information, try this:
select distinct c.ISO2, c.Country, a.job_country,
(
select COUNT(a2.job_country)
from rec_advert a2
where a2.job_country = a.job_country
and a2.status = 1
and a2.`delete` = 0
and a2.days_left >0
) as jobs_no
from rec_countries c, rec_advert a
where c.status = 1
and DATE(a.modified_date) >= CURDATE() - INTERVAL 30 DAY
and c.ISO2 <> '--'
and c.ISO2 <> ''
and c.CountryId = a.job_country
and a.status = 1
and a.`delete` = 0
and a.days_left >0