I need my query to select unix timestamps which range from a particular past date till now?For example I need to select '2013-01-01' till current date. I was able to do it for a particular year. Any help would be appreciated.
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
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 YEAR( FROM_UNIXTIME( mdl_grade_grades.timemodified ) ) =2013
GROUP BY mdl_user.id
To check for a timestamp value between a given datetime in the past, and the current datetime, something like this:
AND mdl_grade_grades.timemodified >= '2013-07-25 15:30'
AND mdl_grade_grades.timemodified < NOW()
Simply replace this line:
AND YEAR(FROM_UNIXTIME(mdl_grade_grades.timemodified)) = 2013
to:
AND FROM_UNIXTIME(mdl_grade_grades.timemodified)
BETWEEN '2012-01-01 12:00'
AND now()
It seems that you are storing unix timestamp in your timemodified column. You should consider changing it to timestamp type - this will allow to take advantage of index on that field. Now, your query (and this query as well) is slow because it has to compute FROM_UNIXTIME() on every row in that table and only then compare year or date.
UPDATE:
If you don't want to change types, using this should make your query work much faster (provided that there is an index on timemodified column):
AND mdl_grade_grades.timemodified
BETWEEN unix_timestamp('2012-01-01 12:00')
AND unix_timestamp(now())
try below query
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
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_grade_grades.timemodified < date('d-m-Y')
GROUP BY mdl_user.id
You can create a Stored Procedure and pass the date as parameter to it.
Here I made it more flexible by adding end date too.
CREATE PROCEDURE `NewProc`(IN StartDate date,IN EndDate date)
BEGIN
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
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_grade_grades.timemodified between StartDate and EndDate
GROUP BY mdl_user.id
END;
AND DATE(FROM_UNIXTIME(mdl_grade_grades.timemodified)) between '2013-01-01' and
DATE(NOW());
Related
We are getting result proper but its taking too much time to execute.Can we optimise query which will take less time to execute.
SELECT c.client_id
FROM client_master c
INNER JOIN user_visit_record u ON u.client_id = c.client_id
WHERE c.dept_id ='1'
AND c.branch_id='1'
AND c.client_status IN('Hot','Warm','Cold','Quotation')
AND u.next_followup_date < '2017-06-01'
AND u.visit_id IN
(SELECT max(visit_id)
FROM user_visit_record
WHERE client_id=c.client_id)
Thanks in advance.
Here is the optimized query:
SELECT c.client_id
FROM client_master c
JOIN (SELECT * FROM user_visit_record u ORDER BY u.visit_id DESC) AS t ON t.client_id = c.client_id
WHERE c.dept_id ='1'
AND c.branch_id='1'
AND c.client_status IN('Hot','Warm','Cold','Quotation')
AND t.next_followup_date < '2017-06-01'
GROUP BY t.clientid
I have Used * in query, you can do is select only required columns,one way of optimising
And MySQL has several existing solutions, check this Article
SELECT c.client_id
FROM
(SELECT *
FROM client_master
WHERE dept_id ='1'
AND branch_id='1'
AND IN('Hot','Warm','Cold','Quotation')) AS c
INNER JOIN
(SELECT *
FROM user_visit_record
WHERE next_followup_date < '2017-06-01'
AND visit_id IN
(SELECT max(visit_id)
FROM user_visit_record
WHERE client_id=c.client_id)) AS u
ON u.client_id = c.client_id
Try this :
SELECT client_id FROM
(
SELECT client_id
FROM client_master
WHERE dept_id ='1' AND branch_id='1' AND client_status IN('Hot','Warm','Cold','Quotation')
) AS c
NATURAL JOIN
(
SELECT client_id
FROM user_visit_record
INNER JOIN (
SELECT client_id, max(visit_id) as max_visit
FROM user_visit_record
GROUP BY client_id
) AS max_user_visit
ON (user_visit_record.client_id = max_user_visit.client_id)
AND (user_visit_record.visit_id = max_visit)
WHERE next_followup_date < '2017-06-01'
) AS u
I have the following query:
SELECT sa.*, d.day, TIME_FORMAT(timefrom.time, '%H:%i') AS time_from, TIME_FORMAT(timeto.time, '%H:%i') AS time_to
FROM staff s
INNER JOIN staff_availability sa
ON sa.staff_id = s.staff_id
INNER JOIN days d
ON d.day_id = sa.day_id
LEFT JOIN time_slots AS timefrom
ON timefrom.time_slot_id = sa.time_from
LEFT JOIN time_slots AS timeto
ON timeto.time_slot_id = sa.time_to
INNER JOIN users u
ON s.user_id = u.user_id
WHERE u.user_id = :user_id
I am using the alias time_from and time_to as the formatted times picked out of the time_slots table which are joined on with the staff_availability table.
The query is returning the following:
staff_availability_id staff_id day_id time_from(join) time_to(join) day time_from (alias) time_to (alias)
Is there any way I can exclude the join columns from the results?
you have to select them manually.
change this
SELECT sa.*
to
SELECT sa.staff_availability_id , sa.staff_id,....--what ever you want to select and dont select those you mentioned
select the columns as,
SELECT sa.staff_availability_id ,sa.staff_id,d.day, TIME_FORMAT(timefrom.time, '%H:%i') AS time_from, TIME_FORMAT(timeto.time, '%H:%i') AS time_to
FROM staff s
INNER JOIN staff_availability sa
ON sa.staff_id = s.staff_id
INNER JOIN days d
ON d.day_id = sa.day_id
LEFT JOIN time_slots AS timefrom
ON timefrom.time_slot_id = sa.time_from
LEFT JOIN time_slots AS timeto
ON timeto.time_slot_id = sa.time_to
INNER JOIN users u
ON s.user_id = u.user_id
WHERE u.user_id = :user_id
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.
There are two tables, one is "users" and another one is "screenings" A user can have multiple records in screenings. I need to compare the date of the earliest records from one's multiple screening record, and see if it has been 30 days from now. How do I do that?
I got a query like this. I want the first screen.date of specific user and compare it to make sure if it has been 30 days from now. I put the AND screening.date + INTERVAL 30 DAY > NOW() that way, but it doesn't work the right way. It compares the date of a user's multiple screenings. But I just want the first one.
SELECT users.id AS user_id, users.first_name, users.last_name, clients.name AS client,
users.social_security_number AS ssn, users.hiredate,
screening.id AS screening_id, screening.date AS screening_date, screening.maileddate AS screening_maileddate
FROM users
INNER JOIN clients
ON(
users.client_id = clients.id
AND users.client_id = '1879'
)
LEFT JOIN screening
ON(
users.id = screening.user_id
)
WHERE
(users.hiredate BETWEEN '2011-01-01' AND '2011-08-14'
OR users.hiredate IS NULL)
AND users.id IN(
SELECT users.id from users
INNER JOIN screening sall
ON(
sall.user_id = users.id
)
INNER JOIN screening s1
ON(
s1.user_id = users.id
AND s1.date BETWEEN '2011-05-15' AND '2011-11-15'
)
INNER JOIN screening s2
ON(
s2.user_id = users.id
AND s2.date BETWEEN '2011-05-15' AND '2011-11-15'
)
INNER JOIN screening s3
ON(
s3.user_id = users.id
AND s3.date BETWEEN '2011-05-15' AND '2011-11-15'
)
INNER JOIN screening s4
ON(
s4.user_id = users.id
AND s4.date BETWEEN '2011-05-15' AND '2011-11-15'
)
INNER JOIN screening s5
ON(
s5.user_id = users.id
AND s5.date BETWEEN '2011-05-15' AND '2011-11-15'
)
INNER JOIN screening s6
ON(
s6.user_id = users.id
AND s6.date BETWEEN '2011-05-15' AND '2011-11-15'
)
WHERE (s1.cholesterol IS NOT NULL
AND s2.ldl IS NOT NULL
AND s3.triglycerides IS NOT NULL)
AND (s4.glucose IS NOT NULL
OR s5.ha1c IS NOT NULL)
)
AND screening.date + INTERVAL 30 DAY > NOW()
GROUP BY users.id
It is much more advisable to simply fetch records from your DB and leave the comparisons and/or other computations to your programming logic. It is far more efficient on your resources and is more readable-cum-maintainable than such large queries.
What check123 said, but specifically, try using this query (or similar), and then using your application to see if the returned result was more than 30 days ago.
SELECT users.id AS user_id, users.first_name, users.last_name, clients.name AS client,
users.social_security_number AS ssn, users.hiredate, screening.id AS screening_id,
screening.date AS screening_date, screening.maileddate AS screening_maileddate
FROM users
INNER JOIN clients ON( users.client_id = clients.id AND users.client_id = '1879' )
LEFT JOIN screening ON( users.id = screening.user_id )
ORDER BY screening_date
LIMIT 1
I want to do the following using a LEFT JOIN (please do not suggest UNION ALL)
SELECT o.*, s.col1, s.col2 FROM order o
INNER JOIN user u ON o.user_id = u.id
IF o.date less than '2011-01-01'
JOIN subscribe s ON u.key = s.key
ELSE
JOIN subscribe s ON u.email = s.email
END IF;
I used the following but can't test it.
SELECT o.*, COALESCE(s1.col1,s2.col1) AS
col1, COALESCE(s1.col2, s2.col2) AS col2
FROM order o INNER JOIN user u ON o.user_id = u.id
LEFT JOIN subscribe s1 ON
(u.key LIKE (CASE o.date >= '2011-01-01 00:00:00'
WHEN TRUE THEN s1.key ELSE NULL END))
LEFT JOIN subscribe s2 ON (u.email LIKE (CASE o.date <
'2011-01-01 00:00:00' WHEN TRUE THEN s.email
ELSE NULL END));
Please correct me if I am wrong.
Thanks.
You don't need to JOIN twice, do it like this:
SELECT o.*, s.col1, s.col2
FROM order o INNER JOIN user u ON o.user_id = u.id
LEFT JOIN subscribe s ON( ( o.date < '2011-01-01' AND u.key = s.key ) OR
( o.date >= '2011-01-01' AND u.email = s.email ) )
And here is a solution that will not do a full table scan if you have indexes on subscribe.key and subscribe.email:
SELECT * FROM
(
( SELECT 0 AS mode, o.date AS odate, o.*, s.col1, s.col2
FROM order o INNER JOIN user u ON o.user_id = u.id
LEFT JOIN subscribe s ON( u.key = s.key ) )
UNION
( SELECT 1 AS mode, o.date AS odate, o.*, s.col1, s.col2
FROM order o INNER JOIN user u ON o.user_id = u.id
LEFT JOIN subscribe s ON( u.email = s.email ) )
)
WHERE ( odate < '2011-01-01' AND mode = 0 ) OR
( odate >= '2011-01-01' AND mode = 1 )