Have 3 Tables... Need to select users that haven't booked a lesson for the next week, and send an email.
Think I'm looking at
WHERE `LESSONS`.`DATE` > CURDATE()
AND `LESSONS`.`DATE` <= (CURDATE() + INTERVAL 7 DAY)
That works to select the range of dates... However I'm then having a problem joining that to the bookings to see if they have booked, and if they HAVEN'T then I need to grab their email address... I'd rather not use PHP to loop through and query data. I obviously just want to run the single query.
As you can probably tell I'm not in the know when it comes to MYSQL.
Help appreciated. Thanks.
USERS
-----------
ID | EMAIL, ETC
LESSONS
-----------
ID | DATE, ETC
BOOKINGS
-----------
ID | LESSON_ID | USER_ID, ETC
You can try something like
SELECT u.*
FROM USERS u LEFT JOIN
Bookings b ON u.ID = b.USER_ID LEFT JOIN
LESSONS l ON b.LESSON_ID = l.ID
AND l.DATE > CURDATE() AND l.DATE <= (CURDATE() + INTERVAL 7 DAY)
WHERE l.ID IS NULL
This should get all users that do not have any bookings for lessons for next week.
Have a look at Introduction to JOINs – Basic of JOINs
This is a nive visual representation of joins.
use in or exists?
SELECT users.* FROM users
WHERE users.id NOT IN
(SELECT Bookings.user_id FROM Bookings JOIN Lessons ON Bookings.lesson_id = lessons.id
WHERE lessons.date > CURDATE() AND lessons.date <= (CURDATE()+INTERVAL7 7 DAY)
There may be syntactical differences in MySQL opposed to SQL server, that I'm more familiar with.
Related
I have created a select query which shows me the correct lines that I need to update:
SELECT `subject`,`ticket_messages`.`ticket_ID` as t,
(SELECT `date` from `ticket_messages` where `ticket_ID`=t ORDER BY `date` DESC LIMIT 1) as d
from `ticket_messages`
LEFT JOIN `tickets` on `ticket_messages`.`ticket_ID`=`tickets`.`ticket_ID`
GROUP BY t
HAVING d<date_sub(curdate(), interval 5 day)
ORDER BY t
I will be using php but working out the query first in phpmyadmin
Right the above query works and gives me the correct lines.
Basically it is listing anything over 5 days old. Don't worry that I am selecting subject and date, that was only so I knew I was getting the correct lines.
The question is how do I turn this into an update query?
It took me a few hours to get this working already.
What I will be updating is this:
UPDATE `tickets` SET `status`=?
Basically it will be looking in the ticket_messages and finding the last message. Which is what my select query does, and then it will update in my "tickets" table the status, if the last date is over 5 days old. The tables are referentially linked.
So I need an Update with a subquery, and I have no idea to go about this.
Ok going to add a bit more. I tried this
UPDATE `tickets` SET `status`=8
WHERE
(
SELECT `subject`,`ticket_messages`.`ticket_ID` as t,
(SELECT `date` from `ticket_messages` where `ticket_ID`=t ORDER BY `date` DESC LIMIT 1) as d
from `ticket_messages`
LEFT JOIN `tickets` on `ticket_messages`.`ticket_ID`=`tickets`.`ticket_ID`
GROUP BY t
HAVING d<date_sub(curdate(), interval 5 day)
ORDER BY t)!=null
I thought the where clause would work if it did not equal null.
Your first query, i don't like it because I really don't see why you use a subSelect, why you use a group by. What do you want for the date ?
Anyways you said you want only the tickets older than 5 days,
SELECT tm.ticket_ID, MAX(`date`) as d
FROM `ticket_messages` as tm
GROUP BY tm.ticket_ID
HAVING d < date_sub(curdate(), interval 5 day)
And that's all for you first query. Tell me if you get the same ID.
Now for the update, you just have to JOIN :
UPDATE `tickets`
INNER JOIN
(SELECT tm.ticket_ID, MAX(`date`) as d
FROM `ticket_messages` as tm
GROUP BY tm.ticket_ID
HAVING d < date_sub(curdate(), interval 5 day)) AS T
ON T.ticket_ID = `tickets`.ticket_ID
SET`status`=?
My table is:
id user date
---|-----|------------|
1 | ab | 2011-03-04 |
2 | ab | 2016-03-04 |
3 | cd | 2009-03-04 |
4 | cd | 2013-03-03 |
5 | ef | 2009-03-03 |
I need to select each distinct user with :
"update" > date more than current date
Result would be:
id user date
---|-----|------------|
2 | ab | 2016-03-04 |
5 | ef | 2016-03-03 |
"expired" > date less than current date
Result would be:
id user date
---|-----|------------|
3 | cd | 2009-03-04 |
I have tried:
SELECT t1.* FROM tmp t1
WHERE t1.date = (SELECT MAX(t2.date)
FROM tmp t2 WHERE t2.user = t1.user
AND YEAR(MAX(t2.date))<(YEAR(CURRENT_TIMESTAMP)-1))
order by user asc
It doesn't work. Result-set has 0 rows.
Any ideas? Thanks. It'll help me so much..
For dates greater than the current date:
select distinct user
from t
where `update` >= curdate();
Actually, I think you want a group by:
select user
from t
group by user
having max(`date`) >= curdate();
This will also work for earlier dates.
A couple of observations:
"It doesn't work" isn't very descriptive of the behavior you observe. It doesn't describe whether the query is executing and is returning unexpected results, or whether the query is returning an error.
The values shown for date values are in an odd non-MySQL format. Standard format for DATE values is YYYY-MM-DD. This leaves us wondering what the actual datatype of the column named date. If it's a character string, with the month and day preceding the year, that presents problems in comparisons. String comparisons are done character by character, from left to right.
The use of the YEAR() function is very strange in this context. You say you want to compare "date" values. The YEAR function extracts the year value from a date. So it looks like your query is only going to be comparing a year.
And again, if the argument to the YEAR() function isn't a DATE datatype, there's going to be an implicit conversion of that argument to DATE... and for that implicit conversion to work correctly, the string will need to be in a format like 'YYYY-MM-DD'.
Also, it looks like the subquery is using an aggregate function MAX() in a WHERE clause. That's not valid. The predicates in the WHERE clause are evaluated when the rows are accessed. The value of the aggregate function will not be available until after the rows are accessed, and the group by operation is performed. If you need a condition on the aggregate, then that can go into a HAVING clause.
Your dates are in a peculiar format of MM/dd/YYYY, which may pose a problem for you when trying any of the answers given here. You should convert 04/03/2011 to 2011-04-03. That being said, assuming your date column really is a MySQL date type, then the following query will give you all distinct "update" users:
SELECT t1.id, t1.user, t1.date, 'update' AS status
FROM antivirus t1
INNER JOIN
(
SELECT user, MAX(date) AS date
FROM antivirus
GROUP BY user
HAVING MAX(date) >= CURDATE()
) t2
ON t1.user = t2.user AND t1.date = t2.date
SQLFiddle
Note that in my Fiddle I had to modify the format of the date inputs from your sample table.
If you also want the "expired" users in the same query, than you can add UNION ALL plus the following:
SELECT t1.id, t1.user, t1.date, 'expired' AS status
FROM antivirus t1
INNER JOIN
(
SELECT user, MAX(date) AS date
FROM antivirus
GROUP BY user
HAVING MAX(date) < CURDATE()
) t2
ON t1.user = t2.user AND t1.date = t2.date
Thanks to #TimBiegeleisen for the answer..
I've tried this code and it works..
This code for showing the 'update' rows:
select a.* from tmp a
inner join
(select user, max(date) as date from tmp group by user)
b on a.user=b.user and a.date=b.date
where year(a.date +interval 1 year) >= year(current_date())
order by a.user
and this for showing the 'expired' rows:
select a.* from tmp a
inner join
(select user, max(date) as date from tmp group by user)
b on a.user=b.user and a.date=b.date
where year(a.date +interval 1 year) < year(current_date())
order by a.user
I hope my question and all the answers can help other's problems..
I have the following 2 tables...
users
user_id, name, age
user_score
score_id, user_id, score, date(timestamp)
The user_score table should keep a log of all scores for all users updated every 2 hours.
So I need to get a list of all user ids that have not had their score updated in the last 2 hours or at all (for new players). I'm guessing I will have to use INNER JOIN?
Any help would be greatly appreciated.
You want a left join or not exists. You simply need all records with no activity in the past two hours (this would include new users too):
select u.*
from users u
where not exists (select 1 from user_score us
where u.user_id = us.user_id and
us.date >= date_sub(now(), interval 2 hour)
);
I'm sorry if the title is missleading, but I didn't know how to sum it up, sorry :(
Basically, I've made a event system that shows events that you can attend.
I got two tables
"events" and "registrations"
The events table contains all information about a single event, datetime of the event, price,, etc...
Everytime a user clicks register on an event, a record is added to the registration table.
A record looks like this: Registrationid, eventid, date, status and userid
Now I use this query to get all passed events:
SELECT * FROM events WHERE Date < CURRENT_DATE() ORDER BY Date ASC
I only want it to show previous events on the user page, if the user has actually attended the event. Is there a way I can check the registration table, and if a record exists for that event; show the event? I can do this is php, but I figured it would be possible via MySQL, though I'm not completely sure.
Is there a query that can handle the job? :)
Sure, that's a pretty simple join operation. Here's how I would do this:
select e.*
from event e join registration r
on (r.event_id=e.event_id)
where r.user_id=123 and e.date < current_date()
order by e.date asc
A couple of other tips:
Avoid using reserved words and data types as column names (e.g. "date")
The default storage engine in MySQL does not support referential integrity. If you need referential integrity, take a peek at InnoDB.
For more on joins in MySQL, check this out: https://dev.mysql.com/doc/refman/5.0/en/join.html
SELECT * FROM events e , registrations r where e.eventid = r.eventid AND e.Date < CURRENT_DATE()
SELECT e.*
FROM events e
JOIN registrations r
ON e.eventid = r.eventid
WHERE Date < CURRENT_DATE()
AND r.userid = <insert id here>
ORDER BY Date ASC
This query would give you all the fields from the events table, where a record in the registrations table has a specific user id.
Example Select with a join with your information:
SELECT * FROM events AS e WHERE e.Date < CURRENT_DATE() JOIN registration AS r ON e.id = r.eventid ORDER BY e.Date ASC
Despite other commenters' suggestion to use a JOIN (which is a decent suggestion), I think it's actually better in this case to use IN plus a subquery:
SELECT *
FROM events
WHERE eventid IN
( SELECT r.eventid
FROM registrations r
WHERE r.userid = ...
)
AND date < CURRENT_DATE()
ORDER
BY date ASC
(replacing the ... with the appropriate user-ID).
Using a JOIN, you can select the registrations rows for the userid, and then get the events data
SELECT
r.*, // Instead of *, you could specify the columns - r.userid, r.status, etc
e.* // Instead of *, you could specify the columns - e.event_name, e.Date, etc
FROM
registrations r
JOIN
events e
ON
r.eventid = e.id
WHERE
r.userid = YOUR_USERID
AND
r.status = ATTENDED
AND
e.Date < CURRENT_DATE()
ORDER BY
e.Date ASC
I'm kind of new to SQL and I can't find the solution to my problem. I have two tables. In table A, I'm storing a lot of comments, each with a unique ID.
In table B, I'm storing every vote (like=1 and dislike=0) for every comment with a datetime. There will be an entry for every vote, so there will be tons of rows for each comment in table A.
I need to retrieve all the comments and sort them such that the weekly most liked comments are at the top, but I'm not sure how.
Here's what I have so far, but not sure how to continue:
SELECT * FROM comment INNER JOIN logs ON comment.c_id=logs.c_id WHERE logs.daterate >= DATE_SUB(CURDATE(), INTERVAL 8 DAY) AND logs.rated=1
To clarify, I need to get all entries from logs with rated = 1 in the past week and sort them by the most frequent c_id in descending order, and get distinct c_id for each row... if that makes sense
Please ask questions if I didn't make it clear enough, thanks!!
SELECT *
FROM comment
INNER JOIN (SELECT comment.c_id,
COUNT(*) AS cnt
FROM comment
INNER JOIN logs ON comment.c_id=logs.c_id
WHERE logs.daterate >= DATE_SUB(CURDATE(), INTERVAL 8 DAY)
AND logs.rated=1
GROUP BY comment.c_id) x ON x.c_id = comment.c_id
ORDER BY x.cnt DESC
Try this -
I have first queried all records from logs table which are rated 1 and are from 7 days from current date and also are ordered based on the count of c_id. Then joined this with the COmments table.
SELECT Comment.* FROM comment C
INNER JOIN (SELECT logs.c_id as c_id,count(logs.c_id) as logcount FROM logs
WHERE logs.rated=1
AND logs.daterate BETWEEN GETDATE() AND DATEADD(day,-7,getdate())
Group by logs.c_id
order by count(logs.c_id) desc) X
ON C.c_id = X.c_id
ORDER BY X.logcount DESC