How would I transpile this query to Laravel style
SELECT
gr.name,
p.ma_status AS status,
COUNT(p.ma_status) AS total
FROM accounts u
LEFT JOIN accounts_prop p ON p.account_id = u.account_id
AND (
SELECT j.iid
FROM accounts_prop AS j
WHERE u.account_id = j.account_id
AND j.ma_status IS NOT NULL
ORDER BY j.von DESC LIMIT 1
) = p.iid
LEFT JOIN `deprecators` gr ON gr.id = p.group_id
LEFT JOIN `deprecators` unit ON unit.id = p.unit_id
LEFT JOIN `deprecators` team ON team.id = p.team_id
WHERE p.group_id IS NOT NULL
AND u.account_status = 'A'
GROUP BY p.ma_status, gr.id
I do not have any idea how would I go with the following statement
LEFT JOIN accounts_prop p ON p.account_id = u.account_id
AND (
SELECT j.iid
FROM accounts_prop AS j
WHERE u.account_id = j.account_id
AND j.ma_status IS NOT NULL
ORDER BY j.von DESC LIMIT 1
) = p.iid
I have a rather complex query to retrieve products & attributes from several tables.
SELECT SQL_CALC_FOUND_ROWS
p.*,
product_shop.*,
product_shop.id_category_default,
pl.*,
pbn.*,
MAX(image_shop.id_image) id_image,
il.legend,
m.name manufacturer_name,
0 as quantity
FROM ps_category_product cp
LEFT JOIN ps_category c ON (c.id_category = cp.id_category)
LEFT JOIN ps_product p ON p.id_product = cp.id_product
INNER JOIN ps_product_shop product_shop ON (product_shop.id_product = p.id_product AND product_shop.id_shop = 1)
LEFT JOIN ps_product_lang pl ON (pl.id_product = p.id_product AND pl.id_shop = 1 AND pl.id_lang = 7)
## ########### Added joins ###########
LEFT JOIN ps_product_base_names pbn ON pbn.id_product = p.id_product
INNER JOIN (
SELECT base_name, MAX(id_product) AS Max_ID_product
FROM ps_product_base_names
WHERE id_product IN (568110,568129,568134,568135,568136,568137,568139,568140,568141,602911,612411,612413,612512,612513,612515,612612,612616,616213,616217)
GROUP BY base_name) groupedpbn
ON (pbn.base_name = groupedpbn.base_name AND pbn.id_product = groupedpbn.Max_ID_product)
## ########### End added ###########
LEFT JOIN ps_image i ON (i.id_product = p.id_product) LEFT JOIN ps_image_shop image_shop ON (image_shop.id_image = i.id_image AND image_shop.id_shop = 1 AND image_shop.cover=1)
LEFT JOIN ps_image_lang il ON (image_shop.id_image = il.id_image AND il.id_lang = 7)
LEFT JOIN ps_manufacturer m ON (m.id_manufacturer = p.id_manufacturer)
WHERE product_shop.active = 1 AND product_shop.visibility IN ("both", "catalog")
AND c.nleft >= 3 AND c.nright <= 4
AND c.active = 1
AND p.id_product IN (568110,568129,568134,568135,568136,568137,568139,568140,568141,602911,612411,612413,612512,612513,612515,612612,612616,616213,616217)
GROUP BY product_shop.id_product
ORDER BY pl.name asc LIMIT 0,30
I have added 2 JOINs (see comment) to retrieve products by their base name and get only 1 result per base name, to show in the main catalog overview page.
This all works fine, but now I would like to get the number of products that have been grouped per base name. Something like:
COUNT(id_product) AS product_variations
So let's suppose that the products with id_product 568110, 602911 & 612413 all have the same base name, the above query will return id_product 612413 as the result.
But how do I get the number of ID's that have been aggregated (3 for the product with id_product 612413) for every product in the result list?
I found a solution here: https://www.periscopedata.com/blog/use-subqueries-to-count-distinct-50x-faster.html
My working query now looks like this:
SELECT SQL_CALC_FOUND_ROWS
p.*,
product_shop.*,
product_shop.id_category_default,
pl.*,
pbn.*,
cnt.product_variations, ## This line was added for the COUNT specified in the JOIN (see below)
MAX(image_shop.id_image) id_image,
il.legend,
m.name manufacturer_name,
0 as quantity
FROM ps_category_product cp
LEFT JOIN ps_category c ON (c.id_category = cp.id_category)
LEFT JOIN ps_product p ON p.id_product = cp.id_product
INNER JOIN ps_product_shop product_shop ON (product_shop.id_product = p.id_product AND product_shop.id_shop = 1)
LEFT JOIN ps_product_lang pl ON (pl.id_product = p.id_product AND pl.id_shop = 1 AND pl.id_lang = 7)
## ########### Added joins ###########
LEFT JOIN ps_product_base_names pbn ON pbn.id_product = p.id_product
INNER JOIN (
SELECT base_name, MAX(id_product) AS Max_ID_product
FROM ps_product_base_names
WHERE id_product IN (568110,568129,568134,568135,568136,568137,568139,568140,568141,602911,612411,612413,612512,612513,612515,612612,612616,616213,616217)
GROUP BY base_name) groupedpbn
ON (pbn.base_name = groupedpbn.base_name AND pbn.id_product = groupedpbn.Max_ID_product)
## This JOIN was added to COUNT aggregated product IDs
LEFT JOIN (
SELECT base_name, COUNT(id_product) AS product_variations
FROM ps_product_base_names
WHERE id_product IN (568110,568129,568134,568135,568136,568137,568139,568140,568141,602911,612411,612413,612512,612513,612515,612612,612616,616213,616217)
GROUP BY base_name) cnt
ON (pbn.base_name = cnt.base_name)
## ########### End added ###########
LEFT JOIN ps_image i ON (i.id_product = p.id_product) LEFT JOIN ps_image_shop image_shop ON (image_shop.id_image = i.id_image AND image_shop.id_shop = 1 AND image_shop.cover=1)
LEFT JOIN ps_image_lang il ON (image_shop.id_image = il.id_image AND il.id_lang = 7)
LEFT JOIN ps_manufacturer m ON (m.id_manufacturer = p.id_manufacturer)
WHERE product_shop.active = 1 AND product_shop.visibility IN ("both", "catalog")
AND c.nleft >= 3 AND c.nright <= 4
AND c.active = 1
AND p.id_product IN (568110,568129,568134,568135,568136,568137,568139,568140,568141,602911,612411,612413,612512,612513,612515,612612,612616,616213,616217)
GROUP BY product_shop.id_product
ORDER BY pl.name asc LIMIT 0,30
To be honest, it works and it seems fast enough in my test environment, but I haven't got a clue if this solution is efficient or not. So any comments to possibly improve on my solution are still welcome.
Thanks, Mattie
I have about 140k raws in all these tables:
SELECT COUNT( DISTINCT p.product_id ) AS total
FROM bh_product p
LEFT JOIN bh_product_description pd ON ( p.product_id = pd.product_id )
LEFT JOIN bh_product_to_store p2s ON ( p.product_id = p2s.product_id )
Is it normal that execution of this query takes about 3 seconds?
All tables have indexes on product_id field.
Can it be somehow improved?
UPDATED:
Original query:
SELECT COUNT( DISTINCT p.product_id ) AS total
FROM bh_product p
LEFT JOIN bh_product_description pd ON ( p.product_id = pd.product_id )
LEFT JOIN bh_product_to_store p2s ON ( p.product_id = p2s.product_id )
WHERE pd.language_id = '2'
AND p.status = '1'
AND p.date_available <= NOW( )
AND p2s.store_id = '0'
AND (
pd.name LIKE '%душевые%'
OR pd.tag LIKE '%душевые%'
OR LCASE( p.model ) = 'душевые'
OR LCASE( p.sku ) = 'душевые'
OR LCASE( p.upc ) = 'душевые'
OR LCASE( p.ean ) = 'душевые'
OR LCASE( p.jan ) = 'душевые'
OR LCASE( p.isbn ) = 'душевые'
OR LCASE( p.mpn ) = 'душевые'
)
UPDATED: It figured out that the server were running other intensive process, that was slowing sql processing.
After turning off other process perfomance become acceptable.
If you are using left join your result will be same with
select count(distinct p.product_id) as total
from bh_product p
because left join could filter nothing by your product_id.
You can start from this query:
SELECT COUNT(
DISTINCT p.product_id ) AS total
FROM bh_product p
INNER JOIN bh_product_description pd
ON p.product_id = pd.product_id
AND pd.language_id = 2
INNER JOIN bh_product_to_store p2s
ON p.product_id = p2s.product_id
AND p2s.store_id = 0
WHERE p.status = '1'
AND p.date_available <= NOW( )
AND (
pd.name LIKE '%душевые%'
OR pd.tag LIKE '%душевые%'
OR 'душевые' IN ( p.model , p.sku , p.upc , p.ean , p.jan , p.isbn , p.mpn ))
But your most weak point here is your WHERE clause. you are trying to search everywhere. That is not very smart. I am pretty sure that p.ean is barcode and can't be equal to душевые same for p.isbn. So you should change your query to do only what you really need to do. But not filter everything with hope to "catch the fish".
Update Check this query (should be much faster then your 1st one):
SELECT COUNT(
DISTINCT p.product_id ) AS total
FROM bh_product p
INNER JOIN bh_product_description pd
ON p.product_id = pd.product_id
AND pd.language_id = 2
INNER JOIN bh_product_to_store p2s
ON p.product_id = p2s.product_id
AND p2s.store_id = 0
I think You are trying to execute query like this
SELECT COUNT( DISTINCT p.product_id ) AS total
FROM bh_product p ,bh_product_description pd,bh_product_to_store p2s where
p.product_id = pd.product_id and p.product_id = p2s.product_id ;
SELECT COUNT(DISTINCT `product_id`) AS `total`
FROM(
SELECT DISTINCT `p`.`product_id`
FROM oc_category_path cp
LEFT JOIN oc_product_to_category p2c ON (cp.category_id = p2c.category_id)
LEFT JOIN oc_product_filter pf ON (p2c.product_id = pf.product_id)
LEFT JOIN oc_product p ON (pf.product_id = p.product_id)
LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id)
LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id)
INNER JOIN `oc_product_filter` AS `pf` ON `p2c`.`product_id` = `pf`.`product_id`
WHERE IF( `p`.`quantity` > 0, 7, `p`.`stock_status_id` ) IN(7)
AND `p`.`date_available` <= NOW()
AND `p`.`status` = '1'
AND `cp`.`path_id` = '452'
AND `pf`.`filter_id` IN(241)
AND pd.language_id = '1'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = '0'
AND cp.path_id = '452'
AND pf.filter_id IN (241)
) AS `tmp`
This line...
LEFT JOIN oc_product_filter pf ON (p2c.product_id = pf.product_id)
... shares a table alias with this line ...
INNER JOIN `oc_product_filter` AS `pf` ON `p2c`.`product_id` = `pf`.`product_id`
That can't happen. So give the second one a different alias...
SELECT COUNT(DISTINCT product_id) total
FROM
( SELECT DISTINCT p.product_id
FROM oc_category_path cp
LEFT
JOIN oc_product_to_category p2c
ON p2c.category_id = cp.category_id
JOIN oc_product_filter pf
ON pf.product_id = p2c.product_id
JOIN oc_product p
ON p.product_id = pf.product_id
JOIN oc_product_description pd
ON pd.product_id = p.product_id
JOIN oc_product_to_store p2s
ON p2s.product_id = p.product_id
JOIN oc_product_filter pf2 -- <-- changed
ON pf.product_id = p2c.product_id
WHERE IF(p.quantity > 0, 7, p.stock_status_id ) IN(7)
AND p.date_available <= NOW()
AND p.status = 1
AND cp.path_id = 452
AND pf.filter_id IN(241)
AND pd.language_id = 1
AND p.status = 1
AND p.date_available <= NOW()
AND p2s.store_id = 0
AND cp.path_id = 452
AND pf2.filter_id IN(241) -- <-- changed
) tmp;
I need to remove the 2nd row of results which contain a duplicate of the total record from the 1st row. My result set is as follows
1 | 1025
1 | NULL --- I need to remove this row
My query is as follows:
SELECT SUM( mdl_quiz.fcpd ) AS cpdtotal, mdl_user.id AS userid
FROM mdl_grade_grades
INNER JOIN mdl_user ON mdl_grade_grades.userid = mdl_user.id
INNER JOIN mdl_grade_items ON mdl_grade_grades.itemid = mdl_grade_items.id
INNER JOIN mdl_quiz ON mdl_grade_items.itemname = mdl_quiz.name
INNER JOIN mdl_course ON mdl_grade_items.courseid = mdl_course.id
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE mdl_user_info_data.fieldid =1
AND mdl_grade_items.itemname IS NOT NULL
AND mdl_user.annualCPDReportActive = 'Y'
AND (
mdl_course.category =27
)
AND mdl_user.id =1025
AND YEAR( FROM_UNIXTIME( mdl_grade_grades.timemodified ) ) =2013
GROUP BY mdl_user.id
WITH ROLLUP
You should remove WITH ROLLUP
more information here.