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
Related
Below is a query I run to extract some data in the past 24 hours.
SELECT
s.symbol,
count(cs.symbol_id) AS mentions
FROM symbols s
LEFT JOIN comments_symbols cs ON cs.symbol_id = s.id
LEFT JOIN comments c ON c.id = cs.comment_id
WHERE c.`date` > DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY (s.symbol)
ORDER BY mentions
DESC LIMIT 15
However, I need 24 hour intervals of data for the past 30 days in order to show a 30-day chart.
Instead of executing this query 30 times for the each day in the past 30 days, is there an approach I can take to do it with just one query execution?
It seems executing this query 30 times per page load may not be the best way to do this, no?
I hope I explained clearly, please let me know if any details are fuzzy.
Let me assume you have a list of dates. If you don't want to list them out, you can generate them:
with recursive dates as (
select curdate() - interval 30 day as dte
union all
select dte + interval 1 day
from dates
where dte < curdate()
)
Second, the LEFT JOIN seems superfluous, because you are filtering the results using LIMIT. However, I'll leave it in. Use a cross join to generate a row for each day and symbol . . . then aggregate:
SELECT s.symbol, COUNT(cs.symbol_id) AS mentions
FROM dates d CROSS JOIN
symbols s LEFT JOIN
comments_symbols cs
ON cs.symbol_id = s.id LEFT JOIN
comments c
ON c.id = cs.comment_id AND
c.date >= d.dte AND
c.date < d.date + interval 1 day
GROUP BY d.dte, s.symbol
ORDER BY d.dte, mentions DESC
Finally, to get 15 per day, let's put that into a CTE and use window functions:
WITH sm as (
SELECT d.dte, s.symbol, COUNT(cs.symbol_id) AS mentions
FROM dates d CROSS JOIN
symbols s LEFT JOIN
comments_symbols cs
ON cs.symbol_id = s.id LEFT JOIN
comments c
ON c.id = cs.comment_id AND
c.date >= d.dte AND
c.date < d.date + interval 1 day
GROUP BY d.dte, s.symbol
)
SELECT cs.*
FROM (SELECT cs.*,
ROW_NUMBER() OVER (PARTITION BY dte ORDER BY mentions DESC) as seqnum
FROM cs
) cs
WHERE seqnum <= 15;
ORDER BY dte, mentions DESC;
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.
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.
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
I have a high scores table that stores a list of scores and dates. I'd like to find all the scores not in the top 10 that are over a month old. I have the following query which is partially what I want:
SELECT userId FROM highscores
WHERE DATEDIFF(FROM_UNIXTIME(date),
DATE_SUB(CurDate(), INTERVAL 1 MONTH)) < 0
ORDER BY score DESC LIMIT 10,18446744073709551615
What it does:
Find all the scores that were submitted at least a month ago and are not in the top 10 of those old scores.
What I'd like it to do:
Find all the scores that were submitted at least a month ago and are not in the top 10 of
all scores
Is that simple?
Edit: The version of MySQL I'm using doesn't support LIMIT it subqueries. When I try it, I receive the following error:
#1235 - This version of MySQL doesn't yet support 'LIMIT &
IN/ALL/ANY/SOME subquery'
Edit 2: I'd actually like to delete these scores from the table, I was just using a SELECT statement since I figured it would be simple to convert the select to a delete, but I'm not too familiar with subqueries and joining on the same table and deleting from there.
how about:
SELECT userId FROM highscores
WHERE DATEDIFF(FROM_UNIXTIME(date),
DATE_SUB(CurDate(), INTERVAL 1 MONTH)) < 0
AND userId NOT IN (SELECT userId FROM highscores ORDER BY score DESC LIMIT 10)
EDIT:
You are correct. MySQL does not allow LIMIT in a subquery when using IN (...).
Here is another solution which I just tested, and should work.
SELECT h.userId
FROM highscores h
LEFT JOIN (SELECT userId FROM highscores ORDER BY score DESC LIMIT 10) as t
ON t.userId = h.userId
WHERE DATEDIFF(FROM_UNIXTIME(date), DATE_SUB(CurDate(), INTERVAL 1 MONTH)) < 0
AND t.userId IS NULL
EDIT #2:
DELETE h.*
FROM highscores h
LEFT JOIN (SELECT userId FROM highscores ORDER BY score DESC LIMIT 10) as t
ON t.userId = h.userId
WHERE DATEDIFF(FROM_UNIXTIME(date), DATE_SUB(CurDate(), INTERVAL 1 MONTH)) < 0
AND t.userId IS NULL
Split it up. First, make a query that gets you the top 10 entries:
SELECT id FROM entries ORDER BY score DESC LIMIT 10
Then write a query that gives you everything older than a month:
SELECT * FROM entries WHERE DATEDIFF(FROM_UNIXTIME(date), DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) < 0
Now combine these into one:
SELECT * FROM entries WHERE DATEDIFF(FROM_UNIXTIME(date), DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) < 0 AND NOT id IN (SELECT id FROM entries ORDER BY score DESC LIMIT 10)
That should do the trick.