I have created one SQL sub-query which was running perfectly.
SELECT o.*, u.*,OD.* FROM orders o
LEFT JOIN order_details OD on o.id = OD.order_id
LEFT JOIN users u ON o.user_id = u.id
WHERE o.order_status = 1 AND o.id NOT IN
(SELECT r.order_id FROM order_rejected_details r WHERE r.courier_id =$courierId)
order by o.id desc
How to write above query with NOT in condition in CakePHP?
You can simply write this query in CakePHP as per below.
In model:
$resultData = $this->query('SELECT o.*,
u.*,
OD.*
FROM orders o
LEFT JOIN order_details OD
ON o.id = OD.order_id
LEFT JOIN users u
ON o.user_id = u.id
WHERE o.order_status = 1
AND o.id NOT IN (SELECT r.order_id
FROM order_rejected_details r
WHERE r.courier_id = $courierid)
ORDER BY o.id DESC');
return $resultData;
Related
i want to translate this code in phpmyadmin to laravel
SELECT AVG(valeur_5), id_client, nom_propriete, prenom_propreite, nom_entreprise, type_utilisatuer
FROM cliets c
INNER JOIN evaluations e on c.id = e.id_client
INNER JOIN users u on u.id = c.id_user
INNER JOIN propreites p on p.id_user = u.id
GROUP BY id_client
If you want to embed raw SQL into your program, just wrap it in a DB::select.
DB::select("SELECT AVG(valeur_5), id_client, nom_propriete, prenom_propreite, nom_entreprise, type_utilisatuer FROM cliets c INNER JOIN evaluations e on c.id = e.id_client INNER JOIN users u on u.id = c.id_user INNER JOIN propreites p on p.id_user = u.id GROUP BY id_client")
Alternatively, you can rewrite it with the Eloquent query builder.
try this:
$orders = DB::table('hrayfis')
->join('evaluations','evaluations.id_herfi','hrayfis.id')
->join('users','users.id','hrayfis.id_user')
->join('propreites','propreites.id_user','users.id')
->select(
DB::raw('avg(valeur_5)','propreites.nom_propriete '))
->groupBy('hrayfis.id')->get();
i have a sql sub-select to list how many orders there are and their total value:
SELECT u.name,
(SELECT COUNT(*) FROM orders o WHERE o.user_id=u.id
) AS order_count,
(SELECT SUM(oi.quantity * p.price)
FROM orders AS o
INNER JOIN order_items AS oi
ON oi.order_id = o.id
INNER JOIN products AS p
ON p.id = oi.product_id
WHERE o.user_id=u.id
) AS total_price
FROM users u
ORDER BY total_price DESC
Any ideas how can i do that without sub-select?
You can convert the correlated subqueries (O(N^2) performance) into LEFT JOIN
SELECT u.name,
o.order_count,
o2.total_price
FROM users u left join (
SELECT user_id, COUNT(*) order_count
FROM orders
GROUP BY user_id
) o
on u.id = o.user_id
left join (
SELECT o.user_id, SUM(oi.quantity * p.price) total_price
FROM orders o
INNER JOIN order_items oi
ON oi.order_id = o.id
INNER JOIN products p
ON p.id = oi.product_id
GROUP BY o.user_id
) o2 on u.id = o2.user_id
ORDER BY total_price DESC;
You can use Left Join
SELECT u.NAME,
AS order_count,
total_price
FROM users u
LEFT JOIN (SELECT Count(*) AS order_count,
user_id
FROM orders
GROUP BY user_id) p
ON o.user_id = u.id
LEFT JOIN (SELECT Sum(oi.quantity * p.price) AS total_price,
o.user_id
FROM orders AS o
INNER JOIN order_items AS oi
ON oi.order_id = o.id
INNER JOIN products AS p
ON p.id = oi.product_id
GROUP BY o.user_id) so
ON so.user_id = u.id
ORDER BY total_price DESC
Here's the same query with one sub query (NOTE not tested for syntax but you get the idea):
select u.name, count(*) orderCount, sum(totalOrder) total order
from users u
join (select userid, o.id, sum(oi.quantity * p.price) totalorder
from orders o
join order_items as oi on oi.order_id = o.orderid
join products p on oi.product_id = p.id
group by userid, o.id) x
on u.id = x.user_id
group by u.name
How can I translate multiple select like this:
select p.idProcesso, p.idParceiro, p.comissao ,p.NProcesso, p.dataPedido , p.nomeCliente,
e.Descricao, p.dataVisita, i.nomeImovel, f.desc, p.file_certificadoProvisorio, p.adenePaga,
(SELECT nome from users as u where u.id = p.idAgencia) as nomeAgencia,
(SELECT nome from users as u where u.id = p.idParceiro) as nomeParceiro
FROM processo as p
LEFT JOIN imovel as i on i.idImovel = p.idImovel
LEFT JOIN familia as f on f.idTipologia = p.idTipologia
LEFT JOIN estadoscertificado as e on e.CodEstadosCertificado = p.idEstado
ORDER BY p.NProcesso desc
into laravel query builder ?
Thank you
Just use the RAW method...
DB::select(DB::raw('select p.idProcesso, p.idParceiro, p.comissao ,p.NProcesso, p.dataPedido , p.nomeCliente, e.Descricao, p.dataVisita, i.nomeImovel, f.desc, p.file_certificadoProvisorio, p.adenePaga, (SELECT nome from users as u where u.id = p.idAgencia) as nomeAgencia, (SELECT nome from users as u where u.id = p.idParceiro) as nomeParceiro FROM processo as p LEFT JOIN imovel as i on i.idImovel = p.idImovel LEFT JOIN familia as f on f.idTipologia = p.idTipologia LEFT JOIN estadoscertificado as e on e.CodEstadosCertificado = p.idEstado ORDER BY p.NProcesso desc'));
I am just trying to figure out on how to optimize the below sequence of queries into a single query.
To be specific, below queries are just like alerts to be displayed to user when he logins into his account.
$sq = "SELECT COUNT(*) as totm FROM login as l
JOIN msgs m on m.id = l.id
WHERE m.tstamp > l.mtstamp AND l.id = $id;";
$sq .= "SELECT COUNT(*) as totp FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 0 AND u.id = $id;";
$sq .= "SELECT COUNT(*) as totq FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 1 AND u.id = $id";
Right now Iam using mysqli_multi_query() to run this multiple queries.
However I have managed to cut it down into a single query
$sq = "SELECT m.totm,p.totp FROM login as l
JOIN info as u on u.id = l.id
LEFT JOIN (SELECT tstamp,id,COUNT(*) as 'totm' FROM msgs GROUP BY id) m
ON m.id = l.id AND m.tstamp > l.mtstamp
LEFT JOIN (SELECT tstamp,cid,type,id,COUNT(*) as 'totp' FROM pst
GROUP BY id) p
ON p.cid = u.cid AND p.tstamp > l.ptstamp AND p.type = 0
AND p.id <> l.id WHERE l.id = $id
LEFT JOIN (SELECT tstamp,cid,type,id,COUNT(*) as 'totp' FROM pst
GROUP BY id) p
ON p.cid = u.cid AND p.tstamp > l.ptstamp AND p.type = 1
AND p.id <> l.id WHERE l.id = $id LIMIT 1";
When I have tried the single query with EXPLAIN STATEMENT the query ouput is too bad, many rows are affected.
When I have performed the same on three queries individually, the result was good. I am not sure should I run multiple queries or try single query.
After googling I have found that groupBY causes severe overhead in joins and for many rows. kindly anyone let me know what would be the better way to approach this. Can anyone me help me for writing a more optimized query. Thank you. Any help is greatly appreciated.
If you're trying to retrieve the count for a specific id, then I recommend combining your queries as subqueries in the select. There's no sense in using GROUP BY since you're looking for the count of a specific id.
SELECT
(SELECT COUNT(*) FROM login as l
JOIN msgs m on m.id = l.id
WHERE m.tstamp > l.mtstamp AND l.id = $id) totm,
(SELECT COUNT(*) FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 0 AND u.id = $id) totp,
(SELECT COUNT(*) FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 1 AND u.id = $id) totq
Contrast this to retrieving counts for every id in which case a GROUP BY on id would be useful:
SELECT t1.id,t1.totm,t2.totp,t3.totq
FROM
(SELECT l.id, COUNT(*) as totm FROM login as l
JOIN msgs m on m.id = l.id
WHERE m.tstamp > l.mtstamp
GROUP BY l.id) t1
LEFT JOIN (SELECT u.id, COUNT(*) as totp FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 0
GROUP BY u.id) t2 ON t1.id = t2.id
LEFT JOIN (SELECT u.id, COUNT(*) as totq FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 1
GROUP BY u.id) t3 ON t2.id = t3.id
I have a select statement like this:
SELECT c.id AS courseid, u.id AS userid
FROM
mdl_user_enrolments ue
join mdl_enrol e on e.id = ue.enrolid
join mdl_user u on u.id = ue.userid
join mdl_course c on c.id = e.courseid
I have another piece of data I want that does not have a direct relationship with the current tables. I have been calling this function in the output loop,
function getLastCourseAccessByUser($courseid, $userid){
global $DB;
return
$DB->get_record_sql('
SELECT FROM_UNIXTIME(time, "%m/%d/%Y") as ftime
FROM mdl_log
WHERE course = '.$courseid.' AND userid = '.$userid.'
ORDER BY time DESC
limit 1
');
}
but would rather get all the data once, and not call back the db.
I am trying this:
SELECT c.id AS courseid, u.id as userid
(
SELECT FROM_UNIXTIME(time, "%m/%d/%Y") as ftime
FROM mdl_log
WHERE course = c.id AND userid = u.id
) AS lastaccessdate
FROM
mdl_user_enrolments ue
join mdl_enrol e on e.id = ue.enrolid
join mdl_user u on u.id = ue.userid
join mdl_course c on c.id = e.courseid
Or, could I call the function directly from the sql like this:
SELECT c.id AS courseid, u.id as userid,
'.getLastCourseAccessByUser(c.id,u.id).' AS lastaccessdate
FROM
mdl_user_enrolments ue
join mdl_enrol e on e.id = ue.enrolid
join mdl_user u on u.id = ue.userid
join mdl_course c on c.id = e.courseid
Thank you.
SELECT c.id AS courseid, u.id AS userid, FROM_UNIXTIME(t.time, "%m/%d/%Y") as ftime
FROM
mdl_user_enrolments ue
join mdl_enrol e on e.id = ue.enrolid
join mdl_user u on u.id = ue.userid
join mdl_course c on c.id = e.courseid
join mdl_log t on t.course = c.id and t.userid = u.id
You can put AND and OR clauses in a join in mysql so you can join on both your conditionals. Though you may want to make it an outer join so that it won't fail the entire query if the conditionals aren't met
Otherwise your sub select option should also work (this one)
SELECT c.id AS courseid, u.id as userid
(
SELECT FROM_UNIXTIME(time, "%m/%d/%Y") as ftime
FROM mdl_log
WHERE course = c.id AND userid = u.id
) AS lastaccessdate
FROM
mdl_user_enrolments ue
join mdl_enrol e on e.id = ue.enrolid
join mdl_user u on u.id = ue.userid
join mdl_course c on c.id = e.courseid
The more data you process on the MySQL Server side, the less traffic is generated between the MySQL Server and your PHP application, thus speeding up the application. I would say to get all the data from the server at once and not go back and forth too many times.
You can also create the getLastCourseAccessByUser function as a stored function in MySQL if you need to re-use it in other applications:
DELIMITER \\
DROP FUNCTION IF EXISTS getLastCourseAccessByUser\\
CREATE FUNCTION getLastCourseAccessByUser (in_course_id INT, in_user_id VARCHAR(50)
RETURNS STRING
BEGIN
SELECT FROM_UNIXTIME(time, "%m/%d/%Y") AS ftime
FROM mdl_log
WHERE course = in_course_id AND userid = in_user_id
ORDER BY time DESC
LIMIT 1
END\\
DELIMITER ;
Then you could use it in your SELECT statement:
SELECT c.id AS courseid,
u.id as userid,
getLastCourseAccessByUser(c.id,u.id) AS lastaccessdate
FROM mdl_user_enrolments ue
JOIN mdl_enrol e on e.id = ue.enrolid
JOIN mdl_user u on u.id = ue.userid
JOIN mdl_course c on c.id = e.courseid