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
Related
How can I combine my two queries in MySQL 5.7:
(windows functions doesn't work)
1: This query is finding all dialogues where more than 10 messages and spaced at least an hour apart.
SELECT `dialog_id`
FROM `messages`
GROUP BY `dialog_id`
HAVING COUNT(*) >= 10
AND MIN(`timestamp`) + INTERVAL 1 HOUR < MAX(`timestamp`)
2: The second query selects two last rows for each dialogue.
SELECT * FROM messages tbl WHERE
(SELECT COUNT(*) FROM messages tbl1 WHERE tbl1.dialog_id = tbl.dialog_id AND tbl1.id >= tbl.id AND
(user_from = :user_from OR user_to = :user_to)) <= 2 ORDER BY dialog_id DESC
So, what I want is to select last two rows for each dialogue that lasted more than an hour and where more than 10 messages were sent.
Though I didn't got you properly is this what you are looking for:
SELECT * FROM messages tbl WHERE
(SELECT COUNT(*) FROM messages tbl1 WHERE tbl1.dialog_id = tbl.dialog_id AND tbl1.id >= tbl.id AND
(user_from = :user_from OR user_to = :user_to)) <= 2
and dialog_id in (SELECT `dialog_id`
FROM `messages`
GROUP BY `dialog_id`
HAVING COUNT(*) >= 10
AND MIN(`timestamp`) + INTERVAL 1 HOUR < MAX(`timestamp`))
ORDER BY dialog_id DESC
One way you can accomplish this with a subquery:
SELECT *
FROM messages tbl
WHERE (
SELECT COUNT(*)
messages tbl1
tbl1.dialog_id = tbl.dialog_id
tbl1.id >= tbl.id
(user_from = :user_from OR user_to = :user_to)) <= 2
and dialog_id in (
SELECT `dialog_id`
FROM `messages`
GROUP BY `dialog_id`
HAVING COUNT(*) >= 10
AND MIN(`timestamp`) + INTERVAL 1 HOUR < MAX(`timestamp`))
ORDER BY dialog_id DESC
You might have to adjust it slightly, since I don't have the full structure of your tables, but the principle would go as follows: get all the dialogue_ids matching your 10 and over an hour criteria, then use it to limit the messages returned from your "Get the most recent two" logic.
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 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
I need to retrieve data from MySQL from one day, but I don't know the interval between two rows (there may be 4 rows from one day and a gap of a week for example).
Let's say I have: (following isn't code)
3 rows where date = 2015-06-15
1 row where date = 2015-06-09
4 rows where date = 2015-06-05
I want to retrieve all 4 rows from 2015-06-05 with
[...] WHERE `date` < '2015-06-07'
or only one row from 2015-06-09 with
[...] WHERE `date` < '2015-06-14'
Is that possible with SQL only?
If I understand correctly, you want to receive one days worth of rows before a given date. I think that would be:
SELECT t.*
FROM table t
WHERE date = (SELECT MAX(t2.date) FROM table t2 WHERE t2.`date` < '2015-06-07')
I think you want something like this:
select * from table
where date = (select max(date) from table where date < '2015-06-14')
Yes. You can do like this:
(SELECT * FROM `table` WHERE DATE(`date`) = '2015-06-15' LIMIT 0, 3)
UNION
(SELECT * FROM `table` WHERE DATE(`date`) = '2015-06-09' LIMIT 0, 1)
UNION
(SELECT * FROM `table` WHERE DATE(`date`) = '2015-06-09' LIMIT 0, 4)
UNION
SELECT * FROM `table` WHERE DATE(`date`) < '2015-06-07'
UNION
(SELECT * FROM `table` WHERE DATE(`date`) < '2015-06-14' LIMIT 0, 1)
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