I have two tables and I would like to join then with a query.
result save the actual entry of results
user_tracking tracks the acceptance and completion of work, users can cancel and accepts work again at a later time.
SELECT *
from
svr1.result r,
svr1.user_tracking u
where
r.uid = u.user_id and r.tid = u.post1
and u.function_name = '7' #7 == accept work
and r.insert_time > '2015-09-23 00:00:00' and r.insert_time < '2015-10-03 00:00:00'
and u.track_time > '2015-09-23 00:00:00' and u.track_time < '2015-10-03 00:00:00'
my result table had 1785 records within the period I wanted to track
but the above query returns 1990 records. I would like to know how can i filter to get the latest date accepted by user only.
in result table: uid,INT, tid,INT, result,VARCHAR and insert_time,TIMESTAMP
in user_tracking table: user_id,INT, post1,VARCHAR function_name,VARCHAR, result,VARCHAR and track_time,TIMESTAMP
the user_tracking function sample records, in this query the track time will change and the rest will remain the same.
Use the GROUP BY command with a MAX() on the required date, this will select the latest date of all the options (assuming all the other columns are equal). Code as follows (need to declare all columns because of the MAX unfortunately):
SELECT r.uid,
r.tid,
r.result,
r.insert_time,
u.user_id,
u.post1,
u.function_name,
u.result,
MAX(track_time)
FROM
svr1.result r,
svr1.user_tracking u
WHERE
r.uid = u.user_id AND r.tid = u.post1
AND u.function_name = '7' #7 == accept work
AND r.insert_time > '2015-09-23 00:00:00' AND r.insert_time < '2015-10-03 00:00:00'
AND u.track_time > '2015-09-23 00:00:00' AND u.track_time < '2015-10-03 00:00:00'
GROUP BY
r.uid,
r.tid
Related
I'm trying to add a condition in my mySQL statement where if the status is >= 6 then it only shlows the dates between fit_appointment_start_date and if the status is <= 5 then it uses the appointment_start_date condition instead. Is there a way to do this in Mysql?
At the moment i'm just doing an (and or) which is bringing back all the records in the condition, but i need it to change the condition depending on the status
This is my SQL.
SELECT j.client_first_name,
u.home_postcode,
j.engineer_id,
j.deposit_taken,
j.men,
j.time_taken,
j.potential_instalation_date,
j.id,
j.status,
j.postcode,
j.calendar_notes,
j.hasinvoice,
u.color,
j.fit_appointment_start_date,
j.fit_appointment_end_date,
j.client_surname,
j.appointment_start_date,
j.appointment_end_date,
u.username AS engineer_username,
j.potential_instalation_notes
FROM jobs j
INNER JOIN users u
ON u.id = j.engineer_id
INNER JOIN status s
ON s.id = j.status
WHERE u.active = 1
AND ( j.fit_appointment_start_date BETWEEN
'2021-05-04 00:00:00' AND '2021-05-04 23:59:59'
OR j.appointment_start_date BETWEEN
'2021-05-04 00:00:00' AND '2021-05-04 23:59:59' )
ORDER BY engineer_username
if the status is >= 6 then it only shlows the dates between fit_appointment_start_date and if the status is <= 5 then it uses the appointment_start_date condition instead.
...
AND CASE WHEN status >= 6
THEN j.fit_appointment_start_date BETWEEN
'2021-05-04 00:00:00' AND '2021-05-04 23:59:59'
WHEN status <= 5
THEN j.appointment_start_date BETWEEN
'2021-05-04 00:00:00' AND '2021-05-04 23:59:59'
END
...
PS. The rows with status IS NULL won't be selected.
I tried to make indexes on my table. But First mysql uses it then that doesn't use the index.
It is my table indexes.
enter image description here
My Query.
EXPLAIN SELECT
COUNT(DISTINCT K.bayiid) AS toplam,
SUM(K.tutar) AS yatirilan,
SUM(IF(K.durum='2', K.tutar*K.toplam,0)) AS kazanc,
SUM(IF(K.durum='-1', K.tutar, 0)) AS kayip,
SUM(IF(K.durum='1', K.tutar,0)) AS devam,
SUM(IF(K.durum='0', K.tutar,0)) AS iptal,
SUM(1) AS oynanan,
SUM(IF(K.durum='2', 1,0)) AS kazanan,
SUM(IF(K.durum='-1', 1,0)) AS kaybeden,
SUM(IF(K.durum='1', 1,0)) AS devameden,
SUM(IF(K.durum='0', 1,0)) AS iptalolan,
U.*
FROM kuponlar AS K
INNER JOIN users AS U ON U.id = K.bayiid AND U.durum != '4' AND U.id = '26689'
WHERE K.durum < 3 AND K.tarih >= '2016-12-01 00:00:00' AND K.tarih <= '2016-12-31 23:59:59'
Query explaination
enter image description here
But i don't want to use USE INDEX or FORCE INDEX. Do you have any idea why mysql works unstable?
ON U.id = K.bayiid
AND U.durum != '4'
AND U.id = '26689'
For clarity, move the last 2 parts to WHERE; leave only the condition(s) that defines the JOIN.
WHERE K.durum < 3
AND K.tarih >= '2016-12-01 00:00:00'
AND K.tarih <= '2016-12-31 23:59:59'
Suggestion: For date ranges, do something like this:
AND K.tarih >= '2016-12-01'
AND K.tarih < '2016-12-01' + INTERVAL 1 MONTH
For K, have
INDEX(bayiid, darum)
INDEX(bayiid, tarih)
(Without knowing the distribution of the data, I cannot predict which is better. The Optimizer will choose.)
If you want to discuss this further, please provide SHOW CREATE TABLE for each table. If there happen to be datatype inconsistencies, that could cause a lot of trouble, and we cannot see it without the SHOW.
Indexing cookbook
I usually find the answer to my questions here. If not, I know that is probably because I haven't looked deep enough. However this time none of the answers I looked through fit my needs. So here it goes:
I want to use MySQL server to build a report from two tables:
ID Email ID Date Spent
----------------------- ---------------------------
A123 a#test.com A123 3.3.14 2.50
B102 b#test.com A123 7.3.14 3.50
yum yum#a.com B102 4.4.14 7.00
(null) (null)
I want to make a report in which for a given timestamp, eg. from 3.1.2014 to 3.31.14, I get a list of all the ID's of the system with the corresponding amount that they have sent, even if they didn't spend anything.
Therefore from the above tables, let's say we want to retrieve the month of March 2014 (from 3.1.2014 to 3.31.14), I would like to get:
ID Spent
------------------
A123 6.00
B102 7.00
yum NULL
I don't mind to have NULL or 0's for those users that didn't spend any money. So far I have gotten this:
SELECT ID,
sum(Spent) AS Spent
FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
GROUP BY expenses.ID
UNION
SELECT users.ID,
NULL AS Spent
FROM users
WHERE users.ID NOT IN
(SELECT expenses.ID
FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
GROUP BY expenses.ID)
ORDER BY ID;
You can check the above code in here.
It works as expected, but in the real case of my database, the amount of rows in the result query is greater that the amount of unique rows in users.
I have checked that all the ID's in the expenses table are in the users tables, which is the case. I have tested with:
SELECT ID FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
AND ID NOT IN (SELECT users.ID FROM users);
and it returns an empty set, which is as expected.
I must be missing something, but I have no clue of what. Could someone please give some insights? I am pretty new to MySQL, and maybe there is a better way of doing this.
I think you want a left outer join rather than a union:
SELECT u.ID, sum(e.Spent) AS Spent
FROM users u left outer join
expenses e
on u.id = e.id and
e.date >= '2014-03-01 00:00:00' and
e.date < '2014-03-31 00:00:00'
GROUP BY u.ID;
Note in the data you have in the SQL Fiddle, this will return four rows, because of the NULL valued row in users.
you can do a join of two tables (Users and Expenses) to get the same result (http://sqlfiddle.com/#!2/738ea6/5). This will be much faster and an understandable query.
SELECT expenses.ID,
sum(Spent) AS Spent
FROM expenses, users
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
AND users.ID = expenses.ID
GROUP BY expenses.ID
ORDER BY ID;
Group by in second query?
SELECT ID,
sum(Spent) AS Spent
FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
GROUP BY expenses.ID
UNION
SELECT users.ID,
NULL AS Spent
FROM users
WHERE users.ID NOT IN
(SELECT expenses.ID
FROM expenses
WHERE expenses.date >= '2014-03-01 00:00:00'
AND expenses.date < '2014-03-31 00:00:00'
GROUP BY expenses.ID)
GROUP BY ID
ORDER BY ID;
I have a table where I want to retreive data every hourly from database in report format.
like
username 8-9 9-10 10-11
====================================
kiran 20 27 33
Ram 25 23 44
Can we get like this in mysql please help.
select username,count(message) as '8-9' from customer_1.audit_trail
inner join inteliviz.users
on customer_1.audit_trail.user_id = inteliviz.users.id inner join
customer_1.carparks on customer_1.carparks.id = customer_1.audit_trail.location_id
where datetime>'2013-08-27 08:00:00' and datetime<'2013-08-27 09:00:00'
group by username limit 1000;
I think you are looking for conditional aggregation:
select username,
sum(datetime >= '2013-08-27 08:00:00' and datetime < '2013-08-27 09:00:00') as "8-9",
sum(datetime >= '2013-09-27 08:00:00' and datetime < '2013-08-27 10:00:00') as "9-10",
sum(datetime >= '2013-08-27 10:00:00' and datetime < '2013-08-27 11:00:00') as "10-11"
from customer_1.audit_trail t inner join
inteliviz.users u
on t.user_id = 8.id inner join
customer_1.carparks cp
on cp.id = t.location_id
group by username
limit 1000;
I also added table aliases to make the query easier to read. And, I changed the single quotes in column aliases to double quotes. It is a good idea to stick to using single quotes for strings and double quotes for aliases (which is consistent with the standard).
try using >= and <=
select username,count(message) as '8-9' from customer_1.audit_trail
inner join inteliviz.users on customer_1.audit_trail.user_id = inteliviz.users.id
inner join customer_1.carparks on customer_1.carparks.id = customer_1.audit_trail.location_id
where datetime>='2013-08-27 08:00:00' and datetime<='2013-08-27 09:00:00'
group by username limit 1000;
your current one looks between 01 and 59
edit:
http://www.artfulsoftware.com/infotree/queries.php#78
you want to be doing something like that and then grouping by hour(datetime)
I currently have the following query;
SELECT a.schedID,
a.start AS eventDate, b.div_id AS divisionID, b.div_name AS divisionName
FROM schedules a
INNER JOIN divisions b ON b.div_id = a.div_id
WHERE date_format(a.start, '%Y-%m-%d') >= '2010-01-01'
AND DATE_ADD(a.start, INTERVAL 5 DAY) <= CURDATE()
AND NOT EXISTS (SELECT results_id FROM results e WHERE e.schedID = a.schedID)
ORDER BY eventDate ASC;
Im trying to basically find any schedules that do not have any results 5 days after the schedule date. My current query has major performance issues. It also times out inconsistently. Is there a different way to write the query? Im at a mental roadblock. Any help is appreciated.
Without antcipating much on the outcome I would suggest the following leads :
* try to remove the date_format as this generates one function call per record. I don't know the format of your column a.start but this should be possible.
* same for DATE_ADD, you could probably put it on the other member like :
a.start <= DATE_SUB(CURDATE(), INTERVAL 5 DAYS)
you get a chance the result is cached rather than being calculated for each line, you could even define it as a parameter upfront
* the NOT EXISTS is very expensive, it seems to mee you could replace this by a left join like :
schedules a LEFT JOIN results e ON a.schedId = e.schedId WHERE e.schedId is NULL
double-check that all join fields are well indexed.
Good luck
Maybe something like:
SELECT
a.schedID, a.start AS eventDate, b.div_id AS divisionID, b.div_name AS divisionName
FROM
schedules a
INNER JOIN divisions b ON b.div_id = a.div_id
WHERE
date_format(a.start, '%Y-%m-%d') >= '2010-01-01'
AND NOT EXISTS (
SELECT
*
FROM
results e
INNER JOIN schedules a2 ON e.schedID = a2.schedID
WHERE
DATE_ADD(a2.start, INTERVAL 5 DAY) <= CURDATE()
AND a2.id = a.id
)
ORDER BY eventDate ASC;
dont know if mysql is same as oracle but are you converting a date to a string here and then comparing it with a string '2010-01-01' ? Can you convvert 2010-01-01 to a date instead so that if there is an index on a.start, it can be used ?
Also does this query definitely return the right answer ?
You mention you want schedules without results 5 days after the schedule date but it looks like you are aksing for anything in the last 5 days ?
a.start >= 1-Jan-10 and start date + 5 days is before today
try this query
SELECT a.schedID,
a.start AS eventDate,
b.div_id AS divisionID,
b.div_name AS divisionName
FROM (SELECT * FROM schedules s WHERE DATE(s.start) >= '2010-01-01' AND DATE_ADD(s.start, INTERVAL 5 DAY) <= CURDATE()) a
INNER JOIN divisions b
ON b.div_id = a.div_id
LEFT JOIN (SELECT results_id FROM results) e
ON e.schedID = a.schedID
WHERE e.results_id = ''
ORDER BY eventDate ASC;