Query gets very slows if i add a where - mysql

SELECT a.emp_id,s.name, s.department,s.register, z.Compoff_Count as Extra, ifnull(COUNT(DISTINCT TO_DAYS(a.punchdate)),0) as Monthly_Count
FROM machinedata a left join
(SELECT a.emp_id, ifnull(COUNT(DISTINCT TO_DAYS(a.punchdate)),0) as Compoff_Count
FROM machinedata a
RIght JOIN time_dimension c on c.db_date = a.punchdate
where ( year(c.db_date) = 2016 and month(c.db_date) = 8 and (c.holiday_flag = 't' or c.weekend_flag ='t' ))
GROUP BY a.emp_id) Z
on z.emp_id = a.emp_id
RIght JOIN time_dimension c on c.db_date = a.punchdate
left join emp s on s.emp_id = a.emp_id
where (year(c.db_date) = 2016 and month(c.db_date) = 8 and c.holiday_flag = 'f' and c.weekend_flag ='f' )
GROUP BY emp_id
The above query works fine.. but if i add s.department='yes' in the last where the query takes more than 40 seconds.
What shall i do to improve the query performance ?

Your initial query can be simplified I believe by using "conditional aggregates" which places case expressions inside the count() function. This avoids repeated sans of data and unnecessary joins to derived tables.
You should also avoid using functions on data to suit where clause conditions i.e. Instead of YEAR() and MONTH() simply use date boundaries. This allows an index on the date column to be used in the query execution.
I'm not sure if you really need to use TO_DAYS() but I suspect it isn't needed either.
SELECT
a.emp_id
, s.name
, s.department
, s.register
, COUNT(DISTINCT CASE WHEN (c.holiday_flag = 't' OR
c.weekend_flag = 't') THEN c.db_date END) AS Compoff_Count
, COUNT(DISTINCT CASE WHEN NOT (c.holiday_flag = 't' OR
c.weekend_flag = 't') THEN a.punchdate END) AS Monthly_Count
FROM time_dimension c
LEFT JOIN machinedata a ON c.db_date = a.punchdate
LEFT JOIN emp s ON a.emp_id = s.emp_id
WHERE c.db_date >= '2016-08-01'
AND c.db_date < '2016-09-01'
GROUP BY
a.emp_id
, s.name
, s.department
, s.register
If this re-write produces correct results then you could try adding and s.department='yes' into the where clause to assess the impact. If it is still substantially slower then get an explain plan and add it to the question. The most likley cause of slowness is lack of an index but without an explain plan it's not possible to be certain.
Please note that this suggestion is just that; and is prepared without sample data and expected results.

Related

What's wrong with my SQL? (MySQL syntax error, code 1064)

I have
select created_at, sales_flat_order.customer_id,
customer_firstname, customer_lastname, customer_email,
sales_flat_order_address.company,
SUM(grand_total)
from sales_flat_order
left join sales_flat_order_address
on sales_flat_order.entity_id = sales_flat_order_address.entity_id
where created_at >= '2016-06-01 05:00:00' /* 5h difference */
and store_id = 1
and `status` = 'Complete'/*
left join customer_entity
on sales_flat_order.customer_id = customer_entity.entity_id*/
group by customer_email;
Runs fine. Comment content produces error with SQL syntax, code 1064. What's the problem?
Same issue now with this:
select customer.entity_id, customer.group_id,
customer.created_at,
sfo.customer_firstname, sfo.customer_lastname,
sfo.customer_email,
sfo.created_at last_order,
count(sfo.customer_id) num_orders,
group_concat(sfo.grand_total separator '|') grand_totals
from customer_entity customer
inner join sales_flat_order sfo
on customer.entity_id = sfo.customer_id
where sfo.created_at >= '2016-06-01 05:00:00'
and sfo.store_id = 1
and sfo.`status` = 'Complete'
left outer join customer_group
on customer.group_id = customer.customer_group_id
where customer_group.customer_group_id
group by customer.entity_id;
Thanks everyone, that all makes ample sense, definitely getting into the hang of it; how's this? It works but tear it up if anything remains amuck.
select customer.entity_id, customer.group_id, `group`.customer_group_code,
customer.created_at,
`order`.customer_firstname, `order`.customer_lastname,
`order`.customer_email, address.company,
`order`.created_at last_order,
count(`order`.customer_id) num_orders,
group_concat(`order`.grand_total separator '|') grand_totals
from customer_entity customer
inner join sales_flat_order `order`
on customer.entity_id = `order`.customer_id
left outer join customer_group `group`
on customer.group_id = `group`.customer_group_id
left outer join sales_flat_order_address address
on `order`.entity_id = address.entity_id
where `order`.created_at >= '2016-06-01 05:00:00'
and `order`.store_id = 1
and `order`.`status` = 'Complete'
group by customer.entity_id;
I know everyone said to add to the group by clause but there is nothing else I want to group by...?
The where clause must be after all of the joins. There are other issues as well, but that's the issue that really breaks things.
If it were me, I'd also fix the group by clause to match the select list, but MySql lets you write non-standard SQL in this way. You may also have a naming conflict when you add the additional table because you haven't qualified the column names. Aliases would make this easier to do Finally, it's possible for your query logic that you want some of the conditional expressions in the where clause to be part of the first ON clause.
If you format your code properly, it's easy to see why your code doesn't work. Your commented LEFT JOIN that caused the error is after the WHERE clause. Also write proper SQL. Alias your table name because long column names are annoying. Put all non-aggregated columns in the GROUP BY clause. Your code won't even run in any other dbms except for maybe MySQL.
select created_at, sales_flat_order.customer_id
, customer_firstname, customer_lastname
, customer_email
, sales_flat_order_address.company
, SUM(grand_total)
from sales_flat_order
left join sales_flat_order_address on sales_flat_order.entity_id = sales_flat_order_address.entity_id
where created_at >= '2016-06-01 05:00:00' /* 5h difference */
and store_id = 1
and `status` = 'Complete'/*
left join customer_entity on sales_flat_order.customer_id = customer_entity.entity_id*/
group by customer_email;

Mysql Query modify

This is my Query I want to get latest record in each group.I have two table t_service_request and t_request_chkpoint
t_service_request
------------
LTS,JFT,CUS_NO,REQUETST_ID...
t_request_chkpoint
------------
LTS ,REQUETST_ID...
Both table match by REQUETST_ID.
I want to group by cus_no in table t_service_request
SELECT S.*, A.ID as CID, A.ENTRY_ID, A.LTS
FROM maintenance.t_service_request S
WHERE JFT IN (
SELECT MAX(JFT)
FROM maintenance.t_service_request
GROUP BY CUS_NO
) LEFT OUTER JOIN maintenance.t_request_chkpoint A
ON S.REQUEST_ID = A.REQUEST_ID where S.COMPANY_ID = '0002' AND S.STATE >= 3 AND A.STATE >= 3
but didn't work any suggestions ?
t_service_request
------------
LTS|JFT|CUS_NO|REQUETST_ID|
t_request_chkpoint
------------
|LTS|REQUETST_ID|
Join above two table(Request_id) and select latest JFT in each CUS_NO
Try this, maybe works;)
SELECT DISTINCT
S.*,
A.ID AS CID,
A.ENTRY_ID,
A.LTS
FROM maintenance.t_service_request S
LEFT JOIN maintenance.t_request_chkpoint A ON A.REQUETST_ID = S.REQUETST_ID AND A.STATE >= 3
WHERE S.JFT = (SELECT MAX(B.JFT)
FROM maintenance.t_service_request B
WHERE B.CUS_NO = S.CUS_NO
GROUP BY B.CUS_NO)
AND S.COMPANY_ID = '0002' AND S.STATE >= 3
I think your sql may have some syntax errors and I am not sure I've misunderstood your requirement or not.
I must admit, I still don't understand what you are asking. Your query, however, is incomplete, and maybe fixing it solves your problem already.
You say you want "to get latest record in each group" and in your query you are looking for the maximum JFT per CUS_NO. Then, however you are only comparing the JFT and not the CUS_NO.
Moreover, your query is syntactically incorrect, as it has two WHERE clauses. Last but not least, (outer) join criteria (state >= 3 here) belongs in the ON clause, not in the WHERE clause.
Here is the corrected query:
select
sr.*,
rc.id as cid,
rc.entry_id,
rc.lts
from maintenance.t_service_request sr
left outer join maintenance.t_request_chkpoint rc on rc.request_id = sr.request_id
and rc.state >= 3
where sr.company_id = '0002' and sr.state >= 3
and (sr.cus_no, sr.jft) in
(
select cus_no, max(jft)
from maintenance.t_service_request
group by cus_no
);

Using count in mysql join

I have been trying to write a sql query to get some stats from bugzilla. Here is the query
select bugs.bug_id AS bug_id,
COUNT(map_pingpong.bug_when) AS re_open,
MAX(map_closetime.bug_when) AS closed_date
from bugs
LEFT JOIN bugs_activity AS map_pingpong
ON ((map_pingpong.bug_id = bugs.bug_id
and map_pingpong.fieldid=15))
LEFT JOIN bugs_activity AS map_closetime
ON ((bugs.bug_id = map_closetime.bug_id
and map_closetime.fieldid=8
and bugs.bug_status = 'CLOSED' ))
where (bugs.assigned_to = 480)
GROUP BY bugs.bug_id
ORDER BY bug_id;
So, the query supposed to return two things
1) Count of an event happening
2) Date of an event happening
So when i break the query into two different queries they are returning right values. If i run it as above, the count values are wrong (Date is correct though). I am not supposed to run two joins on the same table ? or count should not be there when you use join ?
As Barmar said, you have to dissociate the resultsets to get correct counts:
SELECT
bugs.bug_id AS bug_id,
map_pingpong.cnt AS re_open,
map_closetime.mx AS closed_date
FROM bugs
LEFT JOIN (
SELECT bug_id, COUNT(bug_when) AS cnt
FROM bugs_activity
WHERE fieldid = 15
GROUP BY bug_id
) AS map_pingpong ON map_pingpong.bug_id = bugs.bug_id
LEFT JOIN (
SELECT ba.bug_id, MAX(ba.bug_when) AS mx
FROM bugs_activity ba JOIN bugs ON bugs.bug_status = 'CLOSED' AND ba.bug_id = bug.bug_id AND bugs.assigned_to = 480
WHERE ba.fieldid = 8
GROUP BY ba.bug_id
) AS map_closetime ON bugs.bug_id = map_closetime.bug_id
WHERE bugs.assigned_to = 480
GROUP BY bugs.bug_id
ORDER BY bug_id;
As this is correct functionally speaking, it might be a complete disaster in terms of performance so, be careful...

MAX() Function not working as expected

I've created sqlfiddle to try and get my head around this http://sqlfiddle.com/#!2/21e72/1
In the query, I have put a max() on the compiled_date column but the recommendation column is still coming through incorrect - I'm assuming that a select statement will need to be inserted on line 3 somehow?
I've tried the examples provided by the commenters below but I think I just need to understand this from a basic query to begin with.
As others have pointed out, the issue is that some of the select columns are neither aggregated nor used in the group by clause. Most DBMSs won't allow this at all, but MySQL is a little relaxed on some of the standards...
So, you need to first find the max(compiled_date) for each case, then find the recommendation that goes with it.
select r.case_number, r.compiled_date, r.recommendation
from reporting r
join (
SELECT case_number, max(compiled_date) as lastDate
from reporting
group by case_number
) s on r.case_number=s.case_number
and r.compiled_date=s.lastDate
Thank you for providing sqlFiddle. But only reporting data is given. we highly appreciate if you give us sample data of whole tables.
Anyway, Could you try this?
SELECT
`case`.number,
staff.staff_name AS ``case` owner`,
client.client_name,
`case`.address,
x.mx_date,
report.recommendation
FROM
`case` INNER JOIN (
SELECT case_number, MAX(compiled_date) as mx_date
FROM report
GROUP BY case_number
) x ON x.case_number = `case`.number
INNER JOIN report ON x.case_number = report.case_number AND report.compiled_date = x.mx_date
INNER JOIN client ON `case`.client_number = client.client_number
INNER JOIN staff ON `case`.staff_number = staff.staff_number
WHERE
`case`.active = 1
AND staff.staff_name = 'bob'
ORDER BY
`case`.number ASC;
Check below query:
SELECT c.number, s.staff_name AS `case owner`, cl.client_name,
c.address, MAX(r.compiled_date), r.recommendation
FROM case c
INNER JOIN (SELECT r.case_number, r.compiled_date, r.recommendation
FROM report r ORDER BY r.case_number, r.compiled_date DESC
) r ON r.case_number = c.number
INNER JOIN client cl ON c.client_number = cl.client_number
INNER JOIN staff s ON c.staff_number = s.staff_number
WHERE c.active = 1 AND s.staff_name = 'bob'
GROUP BY c.number
ORDER BY c.number ASC
SELECT
case.number,
staff.staff_name AS `case owner`,
client.client_name,
case.address,
(select MAX(compiled_date)from report where case_number=case.number),
report.recommendation
FROM
case
INNER JOIN report ON report.case_number = case.number
INNER JOIN client ON case.client_number = client.client_number
INNER JOIN staff ON case.staff_number = staff.staff_number
WHERE
case.active = 1 AND
staff.staff_name = 'bob'
GROUP BY
case.number
ORDER BY
case.number ASC
try this

Print all rows from one table with a nested MySQL query

I have a MySQL query that I would like to enhance by requiring that all values of client.client_name are printed out in the result, even if no values are found for every row in that table. The current table shows:
client.client_name
Client A
Client B
Client C
The current MySQL query is below:
SELECT X.expr1 AS 'Project Name', SUM(X.expr2) AS 'Total Hours Logged', X.expr3 - sum(X.expr2) AS 'Monthly Hours Remaining', X.expr4 AS 'Last Day', DATEDIFF(X.expr4 , curdate()) AS 'Days Remaining'
FROM
(SELECT
client.client_name AS expr1
, sum(time_records.value) AS expr2
, client.monthly_hours AS expr3
FROM project_objects
INNER JOIN projects
ON projects.id = project_objects.project_id
INNER JOIN time_records
ON time_records.parent_id = project_objects.id
LEFT JOIN client
ON project_objects.project_id = client.project_id
WHERE time_records.parent_type = 'Task'
AND client.start_day_of_month < dayofmonth(curdate())
AND time_records.state = 3
GROUP BY client.client_name
UNION
SELECT
client.client_name AS expr1
, sum(time_records.value) as expr2
, client.monthly_hours AS expr3
FROM projects
INNER JOIN time_records
ON projects.id = time_records.parent_id
LEFT JOIN client
ON projects.id = client.project_id
WHERE time_records.parent_type = 'Project'
AND client.start_day_of_month < dayofmonth(curdate())
AND time_records.state = 3
GROUP BY client.client_name
) X
GROUP BY X.expr1
ORDER BY DATEDIFF(X.expr4 , curdate()
As you can see from the above query - I added a Left Join for the client table, however it doesn't result in printing out all client records - it only prints those for which there are time_records available. I think this is related to the nesting or the order of how I am writing the joins, but can't seem to figure it out. If you have any ideas it would be greatly appreciated. Thanks!
Please try order as below:
FROM client LEFT JOIN project_objects
ON project_objects.project_id = client.project_id
see SQLFiddle for the final solution here: http://sqlfiddle.com/#!2/30362/16