Looking to select a row from the database using DATETIME - mysql

I have the following query
SELECT * FROM ".TBL_FOOT_GAMES." ORDER BY id DESC LIMIT 1
I need to add a WHERE clause on the field date_confirmed.
date_confirmed is a DATETIME type.
I need to select only rows that are within 7 days of the current moment.
MORE CODE
SELECT g.home_user, g.away_user, g.home_score, g.away_score, g.id AS gameid, g.date_confirmed,
hu.username AS home_username, au.username AS away_username, ht.team AS home_team, at.team AS away_team
FROM tbl_foot_games g INNER JOIN tbl_users hu ON hu.id = g.home_user INNER JOIN tbl_users au ON au.id = g.away_user
INNER JOIN tbl_foot_teams ht ON ht.id = g.home_team INNER JOIN tbl_foot_teams at ON at.id = g.away_team
WHERE (g.type = '1' OR g.type = '2' OR g.type = '3' OR g.type = '4') AND g.status = '3' AND g.date_confirmed BETWEEN NOW() AND DATE_SUB(NOW(), INTERVAL 50 WEEK)
ORDER BY g.id DESC LIMIT 1
The statement works fine until I add the WHERE clause for the 50 week interval.

Presuming only seven days in the future (it looks like you're going to list upcoming football games):
SELECT *
FROM `tbl`
WHERE `date_confirmed` BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 1 WEEK)
ORDER BY `id` DESC
LIMIT 1
Please read the documentation first next time; the answers are all there.

... WHERE date_confirmed BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 7 DAY) ...

Have a look at the NOW() and DATE_SUB() functions.
These should let you create a date 7 days ago, then in your where clause you can check that the datetime column is greater than this.

You can use the date_sub function of MySQL to see if the diff is 7 days or less.
SELECT * FROM ".TBL_FOOT_GAMES."
WHERE DATE_ADD(DATE_CONFIRMED, INTERVAL '7 00:00:00' DAYS_SECOND) >= TIMESTAMP(CURDATE())
ORDER BY id DESC LIMIT 1
If you are interested in seeing only 7 days of difference from current date (ignoring the time value), then you can use DATEDIFF function like this:
SELECT * FROM ".TBL_FOOT_GAMES."
WHERE DATEDIFF(CURDATE(), DATE_CONFIRMED) <= 7
ORDER BY id DESC LIMIT 1

Related

MySQL - Using COALESCE with DATE_ADD and DATE_SUB to get next/previous record

I am trying to query MySQL to select the previous and next record. I need help in using COALESCE and DATE_ADD/DATE_SUB together.
SELECT * from `Historical` where `DeltaH` = 'ALTF' and `Date`=
COALESCE(DATE_SUB('2019-01-21', INTERVAL 1 DAY),
DATE_SUB('2019-01-21',INTERVAL 2 DAY),
DATE_SUB('2019-01-21', INTERVAL 3 DAY));
I cannot use the primary key because rows in the table are/will be deleted. The date column also does not necessarily have fixed dates, what I want to find is the next earlier/later date.
SELECT * from `Historical` where `DeltaH` = 'ALTF' and `Date`=
DATE_SUB('2019-01-21', INTERVAL 3 DAY);
The above query seems to work, however I need to query for INTERVAL 1 DAY, in case the date does not exist move to INTERVAL 2 DAY....
select * from `Historical` where `DeltaH` = 'ALTF' and `Date`=
DATE_SUB('2019-01-21', INTERVAL COALESCE(1,2,3,4,5) DAY);
This one does not work either. I understand that the COALESCE() function returns the first non-null value, however I am not able to get it to work using the above query. I have confirmed that data exists for 2019-01-18 but is not being selected. Can you please advise?
I am OK with using an alternate solution.
You can use a subquery to find the most recent date in the table that is less than 2019-01-21 e.g.
SELECT *
FROM `Historical`
WHERE `DeltaH` = 'ALTF' AND `Date`= (SELECT MAX(`Date`)
FROM `Historical`
WHERE `DeltaH` = 'ALTF' AND `Date` < '2019-01-21')
To find the closest date that is later, we just adapt the query slightly, using MIN and >:
SELECT *
FROM `Historical`
WHERE `DeltaH` = 'ALTF' AND `Date`= (SELECT MIN(`Date`)
FROM `Historical`
WHERE `DeltaH` = 'ALTF' AND `Date` > '2019-01-21')
FWIW, I'd write this differently...
SELECT x.*
FROM Historical
JOIN
( SELECT deltah
, MAX(date) date
FROM Historical
WHERE date < '2019-01-21'
GROUP
BY deltah
) y
ON y.deltah = x.deltah
AND y.date = x.date
WHERE x.deltah = 'ALTF';
This seems like the simplest method:
select h.*
from historical h
where h.DeltaH = 'ALTF' and
h2.Date < '2019-01-21'
order by h.Date DESC
limit 1
For best performance, you want an index on (DeltaH, Date).
If you want both the date before and after:
(select h.*
from historical h
where h.DeltaH = 'ALTF' and
h2.Date < '2019-01-21'
order by h.Date desc
limit 1
) union all
(select h.*
from historical h
where h.DeltaH = 'ALTF' and
h2.Date > '2019-01-21'
order by h.Date asc
limit 1
);
I'm not sure if one or both comparisons should be have =, so you can get results on that date.

Date Field last 24H and ORDER BY Other Table

I have a small problem, want to find records with a datefield in the last 24 hours, which also works great:
SELECT * FROM `release` WHERE (date >= now() - INTERVAL 1 DAY)
Now I want to sort the records after a column from another table, also works:
SELECT * FROM `release` AS r JOIN hits as h ON h.id = r.id ORDER BY h.hits DESC LIMIT 0,8
Now to my problem, I get it not to both to cobble, here my attempt (am still very new with Mysql):
SELECT * FROM `release` WHERE (date >= now() - INTERVAL 1 DAY) AS r JOIN hits as h ON h.id = r.id ORDER BY h.hits DESC LIMIT 0,8
But that does not work, why would be nice if someone could explain it to me.
Thank you in advance already times.
Your query have join in wrong place .. for your needs you could use a From with the select result
SELECT *
FROM
( select * from `release`
WHERE (date >= now() - INTERVAL 1 DAY
DESC LIMIT 0,8 ) r
JOIN hits as h ON h.id = r.id
ORDER BY h.hits
You can simply join and add the where clause after that.
SELECT * FROMreleaser JOIN hits as h ON h.id = r.id WHERE (r.date >= now() - INTERVAL 1 DAY) ORDER BY h.hits DESC LIMIT 0,8

MySQL multiple SELECT statements in one query

I'm storing some information in a MySQL table including a date without time.
The date format is a string looking like this: "25.08.2016" (Day.Month.Year).
I want to select the top 50 records from a table descending by a column, but I only want to display the rows with a specific column entry (date).
It is a ranking system and I want to update inactive people.
I would need to combine these 3 queries:
SELECT * FROM `rank` ORDER BY `rank`.`Score` DESC LIMIT 0 , 50;
SELECT * FROM `rank` WHERE NOT (`TimeStamp1` = DATE_FORMAT(NOW(), '%d.%m.%Y') OR `TimeStamp1` = DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 DAY), '%d.%m.%Y'));
UPDATE `rank` SET `inactive` = '1';
Selecting the top 50 people.
Selecting the inactive people of the first query.
Updating the people to inactive.
The most Score is rank 1 and that's why I need DESC, I only want to mark the top 50 people as inactive nothing below, below 50 those people are irrelevant that's why I can't use a statement like this:
SELECT * FROM `rank` WHERE NOT (`TimeStamp1` = DATE_FORMAT(NOW(), '%d.%m.%Y') OR `TimeStamp1` = DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 DAY), '%d.%m.%Y')) ORDER BY `rank`.`Score` DESC LIMIT 0 , 50
Yes, it would select 50 rows but not the top 50.
BTW I'm doing it in php.
And I could solve the problem by fetching:
SELECT * FROM `rank` ORDER BY `rank`.`Score` DESC LIMIT 0 , 50;
Then storing the Accound IDs to an array, then query:
SELECT * FROM `rank` WHERE NOT (`TimeStamp1` = DATE_FORMAT(NOW(), '%d.%m.%Y') OR `TimeStamp1` = DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 DAY), '%d.%m.%Y')) ORDER BY `rank`.`Score` DESC LIMIT 0 , 50;
And compare the Accound IDs to the other result, when no match is found I just break the loop.
Can't I just do it with pure MySQL? Can't I query a thing and then filter the results?
Please help me, any more questions?
Here's my Answer.
UPDATE rank AS target
INNER JOIN (
SELECT w.id
FROM rank AS w
INNER JOIN rank AS e ON e.id = w.id
WHERE (w.`TimeStamp1` = DATE_FORMAT(NOW(), '%Y-%m-%d') OR w.`TimeStamp1` = DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 DAY),'%Y-%m-%d'))
ORDER BY w.`Score` DESC
LIMIT 50
) AS source ON source.id = target.id
SET inactive = 1;
One way of executing queries sequentially is by using transaction.
But that won't combine your queries into one.
BEGIN TRANSACTION;
SELECT *
FROM `rank`
ORDER BY `rank`.`Score` DESC LIMIT 0 , 50;
SELECT *
FROM `rank`
WHERE NOT (`TimeStamp1` = DATE_FORMAT(NOW(), '%d.%m.%Y') OR `TimeStamp1` = DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 DAY), '%d.%m.%Y'));
UPDATE `rank` SET `inactive` = '1';
COMMIT;
Maybe this might be a combination of the three queries:
update rank r
set r.inactive = 1
from
(select a.account_id from rank a
join (select account_id from rank order by rank.score desc limit 0, 50) b on (a.account_id = b.account_id )
where (a.`TimeStamp1` = DATE_FORMAT(NOW(), '%d.%m.%Y') OR a.`TimeStamp1` = DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 DAY), '%d.%m.%Y'))) l
where r.account_id = l.account_id
Let me know if anything fails :)
Edit: swapped rank_id with account_id

Mysql subtracting values using row selected from min timestamp, grouping by id

I've been at this for a few hours now to no avail, pulling my hair out.
Edit: Im wanting to calculate the difference between the overall_exp column by using the same data from 1 day ago to calculate the greatest 'gain' for each user
Currently I'm take a row, then select a row from 1 day ago based on the first rows timestamp then subtract the overall_exp column from the 2 rows and order by that result whilst grouping by user_id
SQL Fiddle: http://sqlfiddle.com/#!2/501c8
Here is what i currently have, however the logic is completely wrong so im pulling 0 results
SELECT rsn, ts.timestamp, #original_ts := SUBDATE( ts.timestamp, INTERVAL 1 DAY), ts.overall_exp, ts.overall_exp - previous.overall_exp AS gained_exp
FROM tracker AS ts
INNER JOIN (
SELECT user_id, MIN( TIMESTAMP ) , overall_exp
FROM tracker
WHERE TIMESTAMP >= #original_ts
GROUP BY user_id
) previous
ON ts.user_id = previous.user_id
JOIN users
ON ts.user_id = users.id
GROUP BY ts.user_id
ORDER BY gained_exp DESC
You can do this with a self-join:
select t.user_id, max(t.overall_exp - tprev.overall_exp)
from tracker t join
tracker tprev
on tprev.user_id = t.user_id and
date(tprev.timestamp) = date(SUBDATE(t.timestamp, INTERVAL 1 DAY))
group by t.user_id
A key here is converting the timestamps to dates, so the comparison is exact.
Try:
select u.*, max(t.`timestamp`)-min(t.`timestamp`) gain
from users u
left join tracker t
on u.id = t.user_id and
t.`timestamp` >= date_sub(date(now()), interval 1 day) and
t.`timestamp` < date_add(date(now()), interval 1 day)
group by u.id
order by gain desc
SQLFiddle here.

Trying to correct a mysql query

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;