simplify this SQL request - php

I have this sql request :
SELECT pl.*, l.loyer, l.charges, l.locataire_id, laire.nom, laire.prenom,
l.chambre_id, c.numero, c.etage, c.maison_id, m.titre_crm
FROM
(
SELECT spl.id, spl.location_id, spl.mois, spl.annee, spl.loyer_paye
from locations sl
LEFT JOIN
(
SELECT * FROM paiement_loyer
union
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
WHERE usl.id not in (SELECT location_id FROM paiement_loyer) ||
(select count(*) FROM paiement_loyer
WHERE location_id = usl.id AND annee = YEAR(NOW())
AND mois=(MONTH(NOW())-1) ) = 0
) spl ON sl.id = spl.location_id
where sl.date_debut <= CURDATE() && CURDATE() <= sl.date_fin
) pl
JOIN locations l ON pl.location_id = l.id
JOIN locataires laire ON l.locataire_id = laire.id
JOIN chambres c ON l.chambre_id = c.id
JOIN maisons m ON c.maison_id = m.id
ORDER BY trim(upper(m.titre_crm)), c.numero, annee, mois
I would like to simplify it, do you have any idea please ?

An attempt at cleaning it up. Note that I think the first LEFT OUTER JOIN could probably be swapped to an INNER JOIN.
I have swapped the 2nd UNIONed query to 2 queries, and for those I have changed them to use LEFT OUTER JOINs which then check that there isn't a match
SELECT pl.id, pl.location_id, pl.mois, pl.annee, pl.loyer_paye,
l.loyer, l.charges, l.locataire_id, laire.nom, laire.prenom,
l.chambre_id, c.numero, c.etage, c.maison_id, m.titre_crm
FROM
(
SELECT spl.id, spl.location_id, spl.mois, spl.annee, spl.loyer_paye
FROM locations sl
LEFT OUTER JOIN
(
SELECT id, location_id, mois, annee, loyer_paye
FROM paiement_loyer
UNION
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
LEFT OUTER JOIN paiement_loyer pl1
ON usl.id = pl1.location_id
WHERE pl1.location_id IS NULL
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
LEFT OUTER JOIN paiement_loyer pl2
ON usl.id = pl1.location_id
AND pl2.annee = YEAR(NOW())
AND pl2.mois=(MONTH(NOW())-1)
WHERE pl2.location_id IS NULL
) spl ON sl.id = spl.location_id
WHERE CURDATE() BETWEEN sl.date_debut AND sl.date_fin
) pl
JOIN locations l ON pl.location_id = l.id
JOIN locataires laire ON l.locataire_id = laire.id
JOIN chambres c ON l.chambre_id = c.id
JOIN maisons m ON c.maison_id = m.id
ORDER BY TRIM(UPPER(m.titre_crm)), c.numero, pl.annee, pl.mois

Related

I'm not able to convert the Mysql query into laravel query builder

I'm struggling to convert this below MySQL query into laravel query builder. It has a lot of joins and subqueries inside. Can someone please help me?
MYSQL query:
SELECT a.id , b.*, a.agent_id, td.contacts, td.addresses
FROM teams a
left join team_details as td on td.team_id = a.id
LEFT OUTER JOIN
(
SELECT m.id, m.due_date, t.team_id, m.department, m.assigned_to , cm.title, u.name
FROM (
SELECT team_id, MAX(due_date) AS due_date
FROM campaign_activities where task_status=false and due_date is not null
GROUP BY team_id
) t JOIN campaign_activities m ON m.team_id = t.team_id AND t.due_date = m.due_date
left join campaign_activity_masters cm on cm.id = m.camp_activity_id
left join users u on u.id = m.assigned_to
) b ON a.id = b.team_id
order by a.id
I'm trying something like below but got stuck with LEFT OUTER JOIN as it has sub query inside :).
DB::table('teams as a')
->leftjoin('team_details as td', 'td.team_id','=','a.id')
->select('a.id', 'b.*', 'a.agent_id','td.contacts','td.addresses')
->leftouterjoin(DB::select(DB::raw('SELECT m.id, m.due_date, t.team_id, m.department, m.assigned_to , cm.title, u.name
FROM (
SELECT team_id, MAX(due_date) AS due_date
FROM campaign_activities where task_status=false and due_date is not null
GROUP BY team_id
) t JOIN campaign_activities m ON m.team_id = t.team_id AND t.due_date = m.due_date
left join campaign_activity_masters cm on cm.id = m.camp_activity_id
left join users u on u.id = m.assigned_to')))
->get();
Any suggestions, please? I want to apply paginate function paginate() instead of get() for this query builder.
I think you should try.
$cards = DB::select("SELECT a.id , b.*, a.agent_id, td.contacts, td.addresses
FROM teams a
left join team_details as td on td.team_id = a.id
LEFT OUTER JOIN
(
SELECT m.id, m.due_date, t.team_id, m.department, m.assigned_to , cm.title, u.name
FROM (
SELECT team_id, MAX(due_date) AS due_date
FROM campaign_activities where task_status=false and due_date is not null
GROUP BY team_id
) t JOIN campaign_activities m ON m.team_id = t.team_id AND t.due_date = m.due_date
left join campaign_activity_masters cm on cm.id = m.camp_activity_id
left join users u on u.id = m.assigned_to
) b ON a.id = b.team_id
order by a.id");
Hope it help you.

Duplicate MethodID in query

I have a query that is using a subquery, and I can't seem to figure out why it is telling me I have duplicate methodID's. The query is supposed to take the data and order by and group by for showing only the latest single result for a given studentID where there could be multiple results with different timestamps but same studentID
SELECT a.*
FROM
( SELECT *
, o.methodName oldName
, n.methodName newName
, s.firstName fName
, s.lastName lName
FROM changeReport r
LEFT
JOIN methodLookup o
ON o.methodID = r.oldMethod
LEFT
JOIN methodLookup n
ON n.methodID = r.newMethod
JOIN students s
ON s.studentID = r.studentID
LEFT
JOIN staffaccounts a
ON r.staffID = a.staffID
WHERE 31 IN (newSubMethod,oldSubMethod)
AND date(timestamp) = CURRENT_DATE
) a
JOIN
( SELECT students.studentID
, MAX(timestamp) timestamp
FROM changeReport r
LEFT
JOIN methodLookup o
ON o.methodID = r.oldMethod
LEFT
JOIN methodLookup n
ON n.methodID = r.newMethod
JOIN students s
ON s.studentID = r.studentID
LEFT
JOIN staffaccounts a
ON r.staffID = a.staffID
WHERE 31 IN (newSubMethod,oldSubMethod)
AND date(timestamp) = CURRENT_DATE
) b
ON b.studentID = a.studentID
AND b.timestamp = a.timestamp;
Any ideas on how this could be?

SELECT product variants SQL

This is my query without variant options
SELECT p.*, pd.`name` AS `product_name`
FROM `product` AS `p`
LEFT JOIN `product_description` AS `pd` ON p.`id` = pd.`product_id`
LEFT JOIN `product_to_variant` AS `pv` ON p.`id` = pv.`product_id`
WHERE p.`status` = 0
GROUP BY p.`id`
ORDER BY p.`id` DESC;
SQLFiddle: http://sqlfiddle.com/#!9/8955b/5
and the follwing query has variant options but it doesn't work
SELECT p.*, pd.`name` AS `product_name`
FROM `product` AS `p`
LEFT JOIN `product_description` AS `pd` ON p.`id` = pd.`product_id`
LEFT JOIN `product_to_variant` AS `pv` ON p.`id` = pv.`product_id`
WHERE p.`status` = 0
AND (pv.`feature_id` = 2 AND pv.`variant_id` = 6)
AND (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
GROUP BY p.`id`
ORDER BY p.`id` DESC;
and I also trying to query but there is no output
SELECT pv.* FROM `product_to_variant` AS `pv`
WHERE (pv.`feature_id` = 2 AND pv.`variant_id` = 2)
AND (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
Do you have any other idea how to receive the products: 14, 15 by specific variant_id 6 AND 11 http://prntscr.com/ect2oh
Here is one method to do what you want:
SELECT p.*, pd.name AS product_name
FROM product p LEFT JOIN
product_description pd
ON p.id = pd.product_id JOIN
product_to_variant pv
ON p.id = pv.product_id
WHERE p.status = 0 AND
((pv.feature_id = 2 AND pv.variant_id = 6) OR
(pv.feature_id = 3 AND pv.variant_id = 11)
)
GROUP BY p.id
HAVING COUNT(DISTINCT feature_id) = 2
ORDER BY p.id DESC;
Notes:
No row can meet your original conditions. Because a column cannot have two values at the same time. Hence the OR rather than AND.
The HAVING clause checks that both values match.
There is no need for a LEFT JOIN to pv, because you are checking values from that table in the WHERE clause -- there have to be matches.
The LEFT JOIN to pa is probably also unnecessary.
Using backticks everywhere just makes the query harder to write and to read.
Maybe like this:
SELECT pv.* FROM `product_to_variant` AS `pv`
WHERE (pv.`feature_id` = 2 AND pv.`variant_id` = 2)
OR (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
Instead of AND, which says, you need both feature_id and variant_id in the results, use OR because it takes both.

select count of rows from 2 tables and merge into one row (mysqli)

i create a web app like facebook by php and mysqli
in my app i have a table for posts , one table for likes , and one table for comments
i want to get the number of comments and likes of each post in one row with his post_id!!!
i try some querys likes this :
select `tblpost`.`post_id`, COALESCE(TCOMM.`comment_num`,0) as `c_num`, COALESCE(TLIKE.`like_num`,0) as `l_num`
from
(select `tblpost`.`post_id`, count(*) as `like_num` from `tblpost` join `tbllikes` on `tbllikes`.`post_id` = `tblpost`.`post_id` group by `tblpost`.`post_id`
) TLIKE
inner join
(select `tblpost`.`post_id`, count(*) as `comment_num` from `tblpost` join `tblcomments` on `tblcomments`.`post_id` = `tblpost`.`post_id` group by `tblpost`.`post_id`) TCOMM
on
TCOMM.`post_id` = TLIKE.`post_id`
but i don't know what's my problem
You can do count distincts with two left joins.
Something like this would work if there are fields like_id and comment_id in the tables tbllikes and tblcomments
SELECT
tblpost.post_id AS post_id,
COUNT(DISTINCT tbllikes.like_id) AS likes,
COUNT(DiSTINCT tblcomments.comment_id) AS comments
FROM tblpost
LEFT JOIN tbllikes ON tbllikes.post_id = tblpost.post_id
LEFT JOIN tblcomments on tblcomments.post_id = tblpost.post_id
GROUP BY tblpost.post_id
First, I think you can greatly simplify your query:
select l.post_id,
COALESCE(c.comment_num, 0) as c_num, COALESCE(l.like_num, 0) as l_num
from (select l.post_id, count(*) as like_num
from tbllikes l
group by l.post_id
) l inner join
(select c.post_id, count(*) as comment_num
from tblcomments c
group by c.post_id
) c
on l.post_id = c.post_id;
This will only get you posts that have both likes and comments. To get what you want, use a left join:
select p.post_id,
COALESCE(c.comment_num, 0) as c_num, COALESCE(l.like_num, 0) as l_num
from tblpost p left join
(select l.post_id, count(*) as like_num
from tbllikes l
group by l.post_id
) l
on l.post_id = p.post_id left join
(select c.post_id, count(*) as comment_num
from tblcomments c
group by c.post_id
) c
on c.post_id = p.post_id;

How Can i Convert this multiple sub query in zend query?

i have the following query which gives desired output in mysql , now i want to implement it in zend query language,
which has different approach to implement the query..
SELECT A.NAME , B.PAYMENT , C.TOTALPROJ , D.TOTALTASK , T.ACTIVETASK , H.HOUR
FROM USERMASTER AS A
LEFT OUTER JOIN
(
SELECT A.U_ID , SUM(A.TOTALTIME * B.RATE) AS PAYMENT
FROM
(
SELECT U_ID , PROJECT_ID ,
SUM(TIME_TO_SEC(CASE WHEN endtime is null then timediff (starttime,starttime)
ELSE timediff (endtime,starttime) END )) / 3600 AS TOTALTIME
FROM LOGMASTER AS A
WHERE PROJECT_ID IS NOT NULL
GROUP BY U_ID , PROJECT_ID
) AS A
INNER JOIN PROJECTTOUSER AS B ON A.PROJECT_ID = B.PROJECT_ID AND A.U_ID = B.U_ID
GROUP BY B.U_ID
) AS B ON A.ID = B.U_ID
LEFT OUTER JOIN
(
SELECT U_ID , COUNT(*) AS TOTALPROJ FROM PROJECTTOUSER GROUP BY U_ID
) AS C ON A.ID = C.U_ID
LEFT OUTER JOIN
(
SELECT ASSIGNED_TO , COUNT(*) AS TOTALTASK FROM TASKTOTARGET GROUP BY ASSIGNED_TO
) AS D ON A.ID = D.ASSIGNED_TO
LEFT OUTER JOIN
(
SELECT ASSIGNED_TO,COUNT(*) AS ACTIVETASK FROM TASKTOTARGET WHERE
IS_ACTIVE = 0 GROUP BY ASSIGNED_TO
) AS T ON A.ID = T.ASSIGNED_TO
LEFT OUTER JOIN
(
SELECT U_ID, SEC_TO_TIME(SUM(TIME_TO_SEC(CASE WHEN endtime is null then
timediff (starttime,starttime) ELSE timediff (endtime,starttime) END ))) AS HOUR
FROM LOGMASTER WHERE INSERT_DATE >= '2013-08-20' AND INSERT_DATE <='2013-08-31'
GROUP BY U_ID
) AS H ON A.ID = H.U_ID
so if any one can guide me in how to create this query in zend then it will be very helpful, and appreciated
Each of your subqueries becomes an new Zend_Query that you can then use just like a table and pass in to the main query.
For example:
$h = new Zend_Db_Select()
->from('LOGMASTER', array('U_ID', 'HOUR' => new Zend_Db_Expr('SEC_TO_TIME(SUM(TIME_TO_SEC(CASE WHEN endtime is null then
timediff (starttime,starttime) ELSE timediff (endtime,starttime) END ))))')
->where("INSERT_DATE >= '2013-08-20'")
->where("INSERT_DATE <= '2013-08-31'")
->group('U_ID');
$mainQuery = new Zend_Db_Select()
->from('a' => 'USERMASTER', array('NAME'))
->joinLeft($h, 'A.ID = H.U_IS', array('HOUR'));
You would create each of your subqueries as its own object and then you can join them into your main query. The last argument of the join function is which columns from the subquery should be added to the main query.
With ZF's fluid interface you can keep joining tables/queries until you have built your entire query.
http://framework.zend.com/manual/1.12/en/zend.db.select.html

Categories