I am trying to extract a list of workers who had their first shift during last week.
Right now, my SQL works if I put a specific worker with a first shift in last week in my where clause (WHERE c.temp_nr ='XXXX'), but when I remove that clause, it just timeout
SELECT MIN(p.start_date), CONCAT(c.first_name, ' ', c.last_name) AS 'c.fullname', c.temp_nr
FROM contactstable c
LEFT JOIN projectlines p on c.temp_nr = p.candidate_number
WHERE c.temp_nr ='XXXX' and c.contact_type = 'Candidate'
HAVING MIN(p.start_date) between DATE_SUB( CURDATE( ) , INTERVAL (dayofweek(CURDATE())+6)
DAY )
AND DATE_SUB( CURDATE( ) , INTERVAL (dayofweek(CURDATE()))
DAY )
Use GROUP BY c.temp_nr
SELECT MIN(p.start_date), CONCAT(c.first_name, ' ', c.last_name) AS 'c.fullname', c.temp_nr
FROM contactstable c
LEFT JOIN projectlines p on c.temp_nr = p.candidate_number
WHERE c.contact_type = 'Candidate'
GROUP BY c.temp_nr
HAVING
MIN(p.start_date)
between
DATE_SUB(CURDATE(), INTERVAL (dayofweek(CURDATE())+6) DAY)
AND DATE_SUB(CURDATE() , INTERVAL (dayofweek(CURDATE())) DAY)
Related
I have a query that shows all workers with their first shift in the last week, it's gathered from two tables and looks like this:
SELECT MIN(p.start_date),
CONCAT(c.first_name, ' ', c.last_name) AS 'c.fullname',
c.temp_nr
FROM contactstable c
LEFT JOIN projectlines p on c.temp_nr = p.candidate_number
WHERE c.contact_type = 'Candidate'
GROUP BY c.temp_nr
HAVING
MIN(p.start_date)
between
DATE_SUB(CURDATE(), INTERVAL (dayofweek(CURDATE())+6) DAY)
AND DATE_SUB(CURDATE() , INTERVAL (dayofweek(CURDATE())) DAY)
My problem is the query times out, so as I understand it I need to add indexes, but after having searched around on multiple sites, I still have no clue how to go about that.
I am using Workbench 8.0
I would suggest that you write the query like this:
SELECT CONCAT(c.first_name, ' ', c.last_name) AS fullname, c.temp_nr,
(SELECT MIN(p.start_date)
FROM projectlines p
WHERE c.temp_nr = p.candidate_number
) as min_start_date
FROM contactstable c
WHERE c.contact_type = 'Candidate'
HAVING min_start_date BETWEEN DATE_SUB(CURDATE(), INTERVAL (dayofweek(CURDATE())+6) DAY) AND
DATE_SUB(CURDATE() , INTERVAL (dayofweek(CURDATE())) DAY);
Then for this, you want indexes on:
contactstable(contact_type, temp_nr, first_name, last_name)
projectlines(candidate_number, start_date).
How can I display a value of NULL where the join did not find any existing values?
SELECT u.display_name Associate
, ROUND(SUM(CASE WHEN w.startdate BETWEEN NOW() AND NOW() + INTERVAL 30 DAY THEN w.timeworked END/3600)) '30 Days'
, ROUND(SUM(CASE WHEN w.startdate BETWEEN NOW() AND NOW() + INTERVAL 60 DAY THEN w.timeworked END/3600)) '60 Days'
, ROUND(SUM(CASE WHEN w.startdate BETWEEN NOW() AND NOW() + INTERVAL 90 DAY THEN w.timeworked END/3600)) '90 Days'
FROM worklog w
JOIN cwd_user u
ON u.user_name = w.author
JOIN cwd_membership m
ON m.directory_id = u.directory_id
AND m.lower_child_name = u.lower_user_name
WHERE m.membership_type = 'GROUP_USER'
AND m.lower_parent_name = 'atl_servicedesk_it_agents'
AND w.startdate BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 90 DAY)
GROUP
BY u. display_name
ORDER
BY u.last_name;
So on my join u.user_name = w.author I want to show all values where there is a u.user_name, even if there is not a w.author. The display_name should still show up, but the values for 40, 60, and 90 days would be NULL. Ideally I want to change the NULL to be 0 instead. Users don't appear in the worklog table unless they have logged work, so right now it only shows two rows for the two people who have. I still want to show everyone that exists in m.lower_parent_name = 'atl_servicedesk_it_agents' to know that they have not logged anything.
Anyone have any ideas?
You can use LEFT JOIN, but you need to be careful about all the joins and the WHERE conditions:
SELECT u.display_name as Associate,
ROUND(SUM(CASE WHEN w.startdate BETWEEN NOW() AND NOW() + INTERVAL 30 DAY THEN w.timeworked END/3600)) as `30 Days`,
ROUND(SUM(CASE WHEN w.startdate BETWEEN NOW() AND NOW() + INTERVAL 60 DAY THEN w.timeworked END/3600)) as `60 Days`,
ROUND(SUM(CASE WHEN w.startdate BETWEEN NOW() AND NOW() + INTERVAL 90 DAY THEN w.timeworked END/3600)) as `90 Days`
FROM cwd_user u JOIN -- Not sure if this should be LEFT JOIN or not
cwd_membership m
ON m.directory_id = u.directory_id AND
m.lower_child_name = u.lower_user_name AND
m.membership_type = 'GROUP_USER' AND
m.lower_parent_name = 'atl_servicedesk_it_agents' LEFT JOIN
worklog w
ON u.user_name = w.author AND
w.startdate BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 90 DAY)
GROUP BY u. display_name
ORDER BY u.last_name;
I'm not sure if the join to m should be an inner join or left join. It depends on whether you want filtering based on that table as well.
I have a query that fetch records from two table. I want if condition in where clause with and operator.
Here is my code :
SELECT sfo.customer_id, sfo.increment_id FROM sales_flat_order sfo
INNER JOIN marketplace_partnertype mptype ON sfo.customer_id = mptype.partner_id
WHERE (mptype.type = 'free' AND sfo.status='complete') AND IF #mptype.type=='free' THEN ((DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 5 DAY ))ELSE (DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 3 DAY );
It shows syntax error near IF #mptype.type=='free'.
It should be appreciable if some help to solve this issues.
Syntax of If condition is:
IF(<cond-expr>, <then-expr>, <else-expr>)
If we change the condition it will be like :-
AND IF (#mptype.type=='free', (DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 5 DAY )) ,(DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 3 DAY ))
Query will look like:
SELECT sfo.customer_id, sfo.increment_id FROM sales_flat_order sfo
INNER JOIN marketplace_partnertype mptype ON sfo.customer_id = mptype.partner_id
WHERE (mptype.type = 'free' AND sfo.status='complete')AND IF (#mptype.type=='free', (DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 5 DAY )) ,(DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 3 DAY )))
The syntax is not correct, you can use case-when condition in the where condition as
SELECT sfo.customer_id, sfo.increment_id FROM sales_flat_order sfo
INNER JOIN marketplace_partnertype mptype ON sfo.customer_id = mptype.partner_id
WHERE (mptype.type = 'free' AND sfo.status='complete')
and
case
when #mptype.type = 'free' then DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 5 DAY )
else DATE( updated_at ) = DATE_SUB( CURDATE( ) , INTERVAL 3 DAY )
end
There's no need to use IF or CASE WHEN:
SELECT
sfo.customer_id,
sfo.increment_id
FROM
sales_flat_order sfo INNER JOIN marketplace_partnertype mptype
ON sfo.customer_id = mptype.partner_id
WHERE
(mptype.type = 'free' AND DATE(updated_at) = DATE_SUB(CURDATE(), INTERVAL 5 DAY)
OR (mptype.type = 'complete' AND DATE(updated_at) = DATE_SUB(CURDATE(), INTERVAL 3 DAY);
but if you want to use case when you could do it this way:
WHERE
mptype.type IN ('free', 'complete')
AND DATE(updated_at) = DATE_SUB(CURDATE(), INTERVAL CASE WHEN mptype.type='free' THEN 3 ELSE 5 END DAY)
I have a query which looks like:
SELECT max(sp.id) as max_id, p.name as player, max(update_time) as last_seen, min(login_time) as first_seen, s.name as last_server,
sum(sp.play_time) as ontime_total,
sum(case when login_time > NOW() - INTERVAL 1 DAY then sp.play_time end) as ontime_day,
sum(case when login_time > NOW() - INTERVAL 7 DAY then sp.play_time end) as ontime_week,
sum(case when login_time > NOW() - INTERVAL 1 MONTH then sp.play_time end) as ontime_month
FROM session_player sp
INNER JOIN players p ON p.id=sp.player_id
INNER JOIN server s ON s.id=sp.server_id
WHERE p.name = ?
The result:
The issue:
Node22 isn't the last server. I am struggling on finding a way to get the server of the last record within this query. How would you solve this issue, if possible without running a second query.
(This query already takes 2-3s seconds depending on the user, if possible I would like to avoid any overhead and in case you see performance optimization possibilities I would appreciate anything.)
This would work, but its performance you can guess (4-5s):
SELECT
MAX( sp.id ) AS max_id, p.name AS player, MAX( update_time ) AS last_seen, MIN( login_time ) AS first_seen,
SUM( sp.play_time ) AS ontime_total,
SUM( CASE WHEN login_time > NOW( ) - INTERVAL 1 DAY THEN sp.play_time END ) AS ontime_day,
SUM( CASE WHEN login_time > NOW( ) - INTERVAL 7 DAY THEN sp.play_time END ) AS ontime_week,
SUM( CASE WHEN login_time > NOW( ) - INTERVAL 1 MONTH THEN sp.play_time END ) AS ontime_month,
(SELECT s.name
FROM session_player sp
JOIN players p ON p.id=sp.player_id
JOIN server s ON s.id=sp.server_id
WHERE p.name = ?
ORDER BY sp.id DESC
LIMIT 1
) as last_server
FROM session_player sp
INNER JOIN players p ON p.id = sp.player_id
INNER JOIN server s ON s.id = sp.server_id
WHERE p.name = ?
After nearly 3 hours of experimenting I got it and even 260 times faster as before:
SELECT MAX(pd.id) AS max_id, pd.name AS player, MAX( pd.update_time ) AS last_seen, MIN( pd.login_time ) AS first_seen,
SUM( pd.play_time ) AS ontime_total,
SUM( CASE WHEN pd.login_time > NOW( ) - INTERVAL 1 DAY THEN pd.play_time END ) AS ontime_day,
SUM( CASE WHEN pd.login_time > NOW( ) - INTERVAL 7 DAY THEN pd.play_time END ) AS ontime_week,
SUM( CASE WHEN pd.login_time > NOW( ) - INTERVAL 1 MONTH THEN pd.play_time END ) AS ontime_month,
(SELECT s.name
FROM session_player sp
INNER JOIN server s ON s.id=sp.server_id
WHERE max(pd.id)=sp.id
) as last_server
FROM (
SELECT sp.id AS id, sp.server_id as server_id, p.name AS name, sp.login_time AS login_time, sp.update_time AS update_time, sp.play_time AS play_time
FROM session_player sp
INNER JOIN players p ON p.id=sp.player_id
WHERE p.name = ?
) as pd
Try this:
SELECT sp.id as max_id, p.name as player, max(update_time) as last_seen,
min(login_time) as first_seen, s.name as last_server,
sum(sp.play_time) as ontime_total,
sum(case when login_time > NOW() - INTERVAL 1 DAY then sp.play_time end) as ontime_day,
sum(case when login_time > NOW() - INTERVAL 7 DAY then sp.play_time end) as ontime_week,
sum(case when login_time > NOW() - INTERVAL 1 MONTH then sp.play_time end) as ontime_month
FROM session_player sp
INNER JOIN players p ON p.id=sp.player_id
INNER JOIN server s ON s.id=sp.server_id
WHERE p.name = ?
group by sp.player_id
order by sp.id desc limit 1
I have a query like below:
Result gives #sold_count:=SUM(I.quantity) = 10, but #sold_count = 0,
so calculations are all 0.
What should be wrong here?
SET #sold_count :=0;
SELECT
#sold_count:=SUM(I.quantity),
#sold_count,I.from_widget,COUNT(from_widget) as order_count,
(#sold_count * buy_price) as ciro,
(#sold_count * list_price) as liste_ciro,
(#sold_count * widget_price) as vitrin_ciro,
P.*
FROM
tbl_products P
LEFT JOIN tbl_order_items I on I.product_id = P.id
WHERE
P.publish_date BETWEEN DATE_SUB( CURDATE( ) ,INTERVAL 3 MONTH ) AND DATE_SUB( CURDATE( ) ,INTERVAL 0 MONTH )
GROUP BY I.from_widget,I.product_id
ORDER BY publish_date DESC
Don't use variables. Just:
SELECT
SUM(I.quantity),
I.from_widget,
COUNT(from_widget) AS order_count,
SUM(I.quantity) * buy_price AS ciro,
SUM(I.quantity) * list_price AS liste_ciro,
SUM(I.quantity) * widget_price AS vitrin_ciro,
P.*
FROM
tbl_products P
LEFT JOIN tbl_order_items I
ON I.product_id = P.id
WHERE
P.publish_date BETWEEN DATE_SUB( CURDATE( ) , INTERVAL 3 MONTH )
AND DATE_SUB( CURDATE( ) , INTERVAL 0 MONTH )
GROUP BY I.from_widget,
I.product_id
ORDER BY publish_date DESC ;
You could also make the query a nested one, if you don't like using SUM(quantity) many times:
SELECT
sum_quantity * buy_price AS ciro,
sum_quantity * list_price AS liste_ciro,
sum_quantity * widget_price AS vitrin_ciro,
tmp.*
FROM
( SELECT
SUM(I.quantity) AS sum_quantity,
I.from_widget,
COUNT(from_widget) AS order_count,
buy_price,
list_price,
widget_price,
P.*
FROM
tbl_products P
LEFT JOIN tbl_order_items I
ON I.product_id = P.id
WHERE
P.publish_date BETWEEN DATE_SUB( CURDATE( ) , INTERVAL 3 MONTH )
AND DATE_SUB( CURDATE( ) , INTERVAL 0 MONTH )
GROUP BY I.from_widget,
I.product_id
) AS tmp
ORDER BY publish_date DESC ;