Using Groupby and Orderby on same query - mysql

SELECT *
FROM
(
SELECT com_jobcard.job_card_num,
sum( worked_qty ),employee.emp_name
FROM timer_completed
INNER JOIN process ON process.id = timer_completed.process_id
INNER JOIN com_jobcard ON com_jobcard.id = timer_completed.job_card_id
INNER JOIN employee ON employee.id = timer_completed.employee_id
AND process.id = '611'
AND timer_completed.group_id = '60'
AND timer_completed.report_date = DATE_ADD(CURDATE(), INTERVAL -1 DAY)
ORDER BY com_jobcard.id DESC
) AS tmp_table
GROUP BY com_jobcard.job_card_num
In this code I'm using Group by option but I need the result in descending order of com_jobcard.id if I use the above query it returns:
#1054 - Unknown column 'com_jobcard.job_card_num' in 'group
statement' .
please help me .

Use
GROUP BY tmp_table.job_card_num

Two things:
1) All Columns in the Sub Query need to be Named. This will clear error #1054
sum( worked_qty ) as 'WorkedTotal'
2) Order by is only available in Subqueries if you are using the 'Top Select' clause . You will need to use Order by Where you have group by and vice versa

You're unnecessarily nesting your query here. You can order an aggregate query result set by putting the ORDER BY after the GROUP BY. Also, like Gordon pointed out in his comment, you're abusing the nonstandard MySql extension to GROUP BY. This will make you crazy unless you learn about it. https://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html
Try refactoring your query like this:
SELECT com_jobcard.job_card_num,
sum( worked_qty),
employee.emp_name,
com_jobcard.id
FROM timer_completed
JOIN process ON process.id = timer_completed.process_id
JOIN com_jobcard ON com_jobcard.id = timer_completed.job_card_id
JOIN employee ON employee.id = timer_completed.employee_id
AND process.id = '611'
AND timer_completed.group_id = '60'
AND timer_completed.report_date = DATE_ADD(CURDATE(), INTERVAL -1 DAY)
GROUP BY com_jobcard.job_card_num, employee.emp_name, com_jobcard.id
ORDER BY com_jobcard.id DESC
Besides being simpler than your proposed query, this handles GROUP BY correctly and yields the order you've specified.

Related

How to optimize the product fetching query

I have used below query for product listing. Query is working fine but it takes approximately 0.4534 seconds. How can I optimize the same query.
SELECT SQL_CALC_FOUND_ROWS DISTINCT tp.prod_id, tp.prod_name, tp.prod_shop, tp.prod_retail_price, tp.prod_sale_price, tp.prod_initial_price, tp.prod_stock, ts.shop_id, ts.shop_name, ts.shop_logo, ts.shop_description, ts.shop_title, tu.user_profile_image, ( SELECT pdiscount_price FROM tbl_product_discounts tpd WHERE tpd.pdiscount_product_id = tp.prod_id AND tpd.pdiscount_qty = '1' AND( ( tpd.pdiscount_start_date = '0000-00-00' OR tpd.pdiscount_start_date < NOW()) AND( tpd.pdiscount_end_date = '0000-00-00' OR tpd.pdiscount_end_date > NOW()) ) ORDER BY tpd.pdiscount_priority ASC, tpd.pdiscount_price ASC LIMIT 1 ) AS discount FROM tbl_products tp LEFT JOIN tbl_shops ts ON tp.prod_shop = ts.shop_id AND ts.shop_is_deleted = 0 INNER JOIN tbl_users tu ON ts.shop_user_id = tu.user_id WHERE tp.prod_is_deleted = '0' LIMIT 0, 20
Without checking you table or Requirement :
Try to use group by instead of DISTINCT
Do not use sub query if possible .
Try To use indexing in you table .
This will help you to optimize you query.

How to convert sub query to joins?

I am using this query in my opencart site
SELECT MIN(tmp.date_added) AS date_start,
MAX(tmp.date_added) AS date_end,
COUNT(tmp.order_id) AS `orders`,
SUM(tmp.products) AS products,
SUM(tmp.tax) AS tax,
SUM(tmp.total) AS total
FROM
( SELECT o.order_id,
( SELECT SUM(op.quantity)
FROM `oc_order_product` op
WHERE op.order_id = o.order_id
GROUP BY op.order_id
) AS products,
( SELECT SUM(ot.value)
FROM `oc_order_total` ot
WHERE ot.order_id = o.order_id
AND ot.code = 'tax'
GROUP BY ot.order_id
) AS tax,
o.total,
o.date_added
FROM `oc_order` o
WHERE o.order_status_id > '0'
AND DATE(o.date_added) >= '2015-03-01'
AND DATE(o.date_added) <= '2016-04-19'
GROUP BY o.order_id
) tmp
GROUP BY WEEK(tmp.date_added)
ORDER BY tmp.date_added DESC
LIMIT 0,60
Queries like this make my site very slow. Is there any easy way to convert this query from sub query to joins.
Here is the output of above query
WEEK will have a hiccup around the first of the year -- there will be two partial weeks.
We are now in "week" 16 of 2016. That corresponds to slightly different days of 2015; did you want them combined?
Because of those hiccups with WEEK, you had better change the final ORDER BY to WEEK(tmp.date_added) DESC
The FROM ( SELECT ... ) is probably fine. Is that what you are asking about?
The two ( SELECT SUM ... ) AS ... are probably optimal, or nearly so. Is that what you are asking about?
However, you probably do need some indexes:
oc_order_total: INDEX(code, order_id) -- in that order
oc_order_product: INDEX(order_id)
Change DATE(o.date_added) >= '2015-03-01' to o.date_added >= '2015-03-01' (etc) so that INDEX(date_added) can be used.
If this can be only '1': o.order_status_id > '0', then change it to o.order_status_id = 1 so that INDEX(order_status_id, date_added) can be used.

MySQL DISTINCT not Filtering out

I have the folowing sql query:
SELECT DISTINCT(tbl_products.product_id), tbl_products.product_title,
tbl_brands.brand_name, tbl_reviews.review_date_added,
NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
ORDER BY tbl_reviews.review_date_added DESC
That needs to filter out any duplicate product_id's unfortunatly selecting tbl_reviews.review_date_added makes each record unique which means DISTINCT will not work anymore.
Is there any otherway of doing this query so that product_id is still unique?
I did do the GROUP BY and the problem is I display the tbl_reviews.review_date_added on a website and it selects the oldest date. I need the newest date.
Regards
With the description given, it's a bit hard to be certain, but if review_date_added is the only problem, it seems like you want the MAX() of that date?
If the following doesn't help, please could you give example data, example output, and a description of how you want the output to be created?
SELECT
tbl_products.product_id,
tbl_products.product_title,
tbl_brands.brand_name,
MAX(tbl_reviews.review_date_added) AS review_date_added,
NOW() AS time_now
FROM
tbl_products
INNER JOIN
tbl_reviews
ON tbl_products.product_id = tbl_reviews.product_id
INNER JOIN
tbl_brands
ON tbl_products.brand_id = tbl_brands.brand_id
GROUP BY
tbl_products.product_id,
tbl_products.product_title,
tbl_brands.brand_name
ORDER BY
MAX(tbl_reviews.review_date_added) DESC
Distinct works for the entire row. The parenthesis are just around the field:
distinct (a), b, c === distinct a, b, c
A straightforward solution is group by. You can use min to select the oldest date.
select tbl_products.product_id
, min(tbl_products.product_title)
, min(tbl_brands.brand_name)
, min(tbl_reviews.review_date_added)
, NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
GROUP BY
tbl_products.product_id
ORDER BY
min(tbl_reviews.review_date_added) DESC
Note that if a product can have multiple brands, this will pick the lowest one.
Try this:
SELECT pr.product_id, pr.product_title,
bd.brand_name,
(SELECT MAX(rev.review_date_added) FROM tbl_reviews rev
WHERE pr.product_id = rev.product_id) AS maxdate,
NOW() AS time_now
FROM tbl_products pr INNER JOIN tbl_reviews re
ON pr.product_id = re.product_id
INNER JOIN tbl_brands bd
ON pr.brand_id = bd.brand_id
GROUP BY pr.product_id
ORDER BY re.review_date_added DESC
or (as suggested by #Hogan)
SELECT pr.product_id, pr.product_title,
bd.brand_name, md.maxdate
NOW() AS time_now
FROM tbl_products pr INNER JOIN tbl_reviews re
ON pr.product_id = re.product_id
INNER JOIN tbl_brands bd
ON pr.brand_id = bd.brand_id
INNER JOIN (SELECT product_id, MAX(review_date_added) AS maxdate
FROM tbl_reviews rev GROUP BY product_id) md
ON pr.product_id = md.product_id
GROUP BY pr.product_id
ORDER BY re.review_date_added DESC
I combined the answer of Andomar with some changes you will find here.
SELECT tbl_products.product_id, tbl_products.product_title,
tbl_products.product_date_added, tbl_brands.brand_name,
MAX(tbl_reviews.review_date_added) AS review_date_added, NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
GROUP BY tbl_products.product_id
ORDER BY MAX(tbl_reviews.review_date_added) DESC
Works beautifully and shows the newest date at tbl_reviews.review_date_added.
Regards

MySQL sum of sub queries

I have quite a long query that is causing me some problems. For the first sub-query I keep getting the error: "MySQL server version for the right syntax to use near 'SELECT project.project_total_num_hours_quoted FROM project inner join time_recor' at line 5".
The subquery in question is:
sum(SELECT
project.project_total_num_hours_quoted
FROM
project inner join time_recording using(project_id)
WHERE
project.company_id = company.company_id
AND project_is_retainer != 1
AND time_recording.time_recording_event_start_datetime >= '2011-01-01' AND time_recording.time_recording_event_stop_datetime <= '2011-03-01'
group by project_id
) AS hours_quoted,
This returns a set of results. In the larger query I simply want to have the sum.
SELECT
SUM((unix_timestamp(time_recording.time_recording_event_stop_datetime)-unix_timestamp(time_recording.time_recording_event_start_datetime))/3600) AS total_time,
company.company_label,
sum(SELECT
project.project_total_num_hours_quoted
FROM
project inner join time_recording using(project_id)
WHERE
project.company_id = company.company_id
AND project_is_retainer != 1
AND time_recording.time_recording_event_start_datetime >= '2011-01-01' AND time_recording.time_recording_event_stop_datetime <= '2011-03-01'
group by project_id
) AS hours_quoted,
(SELECT SUM(project.project_total_num_hours_quoted)
FROM project
INNER JOIN time_recording ON project.project_id = time_recording.project_id
WHERE time_recording.time_recording_event_start_datetime>='2011-01-01'
AND project_is_retainer!=1
AND time_recording.time_recording_event_stop_datetime<='2011-03-01'
AND project.company_id!=1
) AS total_hours_quoted,
(
SELECT
SUM((unix_timestamp(time_recording.time_recording_event_stop_datetime)-unix_timestamp(time_recording.time_recording_event_start_datetime))/3600)
FROM time_recording
INNER JOIN project ON time_recording.project_id = project.project_id
WHERE project.company_id!=1
AND project_is_retainer!=1
AND time_recording.time_recording_event_start_datetime>='2011-01-01'
AND time_recording.time_recording_event_stop_datetime<='2011-03-01'
)
AS total_hours
FROM time_recording
INNER JOIN project ON time_recording.project_id = project.project_id
INNER JOIN company ON project.company_id = company.company_id
WHERE company.company_id!=1
AND project_is_retainer!=1
AND time_recording.time_recording_event_start_datetime>='2011-01-01'
AND time_recording.time_recording_event_stop_datetime<='2011-03-01'
GROUP BY company.company_id
ORDER BY total_time desc
LIMIT 7
In your first subquery, you don't need the group by if you sum it in the outer query. And you are missing the ON clause.
SELECT project.project_total_num_hours_quoted
FROM project inner join time_recording
ON project.id=time_recording.project_id
WHERE
project.company_id = company.company_id
AND project_is_retainer != 1
AND time_recording.time_recording_event_start_datetime >= '2011-01-01'
AND time_recording.time_recording_event_stop_datetime <= '2011-03-01'
I would strongly recommend scrapping this and starting again.
Several, if not all, the subselects could be merged into a single SELECT statement. The outer SELECT is an aggregate operation which selects non-aggregated values not included in the GROUP BY clause. MySQL does not optimize push-predicates. And you've got redundant joins in the query.

Need Help for DATE_FORMAT( p.date, '%Y-%m-%d' ) = CURDATE( )

I have a query for getting today's records from table. I have inserted the date field by using now().
select u.*,p.* from user_brands as u inner join products as p where u.parent_id = p.cat_id and date_format( p.date, '%Y-%m-%d' ) = curdate( )
By using this query every first time I am getting empty results, once if I refresh the page I am getting the results. Why is it not returning values for the first time?
A simpler version is to use condition DATE(p.date) = CURDATE(). As for the empty first set, no idea. You mention that you refresh a page, does your query work in mysql command line or other non-web browser interface?
try with this query:
select u.*,p.* from user_brands as u inner join products as p where u.parent_id = p.cat_id and YEAR(p.date) = YEAR(now()) and MONTH(p.date) = MONTH(now()) and DAY(p.date) = DAY(now())