MySQL get row closest to NOW() - mysql

I have a table with User data such as name, address etc and another table which has a paragraph of text about the user. The reason that they are separate is because we need to record all the old about data. So if the user changes their paragraph - the old one should still be stored. Each bit of about data has a primary key aboutMeID. What I want to do is have a join that pulls their name, address etc and the latest bit of aboutMe data from the other table.
I am not sure though how I can order the join to only get the latest about me data.
Can someone help?

Assuming you have a column with the dateEntered field you could just say
select col1, col2, col3 from aboutme order by dateEntered desc limit 1
This will give you the row that is newest.

Where you have two tables to join, the subquery asks the table with the older paragraphs to give just the last one, ordered by date (datestamp DESC) and match it up based on your user ID. Finally the outer query limits the whole thing to just the user in question (#UserID).
SELECT name, address, aboutme
FROM users
LEFT JOIN
(SELECT aboutme FROM oldertable
WHERE aboutMeID = users.id
ORDER BY datestamp DESC
LIMIT 1)
WHERE users.id = #UserID;

you should sort it by date of change descendently and limit it to one record (LIMIT 1)

subselect variant:
select name,
address,
(select aboutme
from ABOUTTABLE
where USERDATA.userid = ABBOUTTABLE.userid order by datefield limit 1)
from USERDATA

This is rather tricky and probably would be slow but it is done through depended subquery.
SELECT name, address, aboutme.text as aboutme
FROM users
LEFT JOIN aboutme ON aboutMeID = (SELECT aboutMeID FROM aboutme
WHERE user_id = users.id
ORDER BY datestamp DESC
LIMIT 1)
Not sure is it faster than #JYelton solution, it is something you'd have to test yourself.

Related

Mysql multiple select statements in single query with if condition

i have table
users
with id,name,type,active,...
i have another table orders
with orderid,userid,...
i want to update orders table in such a way that
UPDATE orders SET userid=(SELECT id FROM users WHERE type="some" and active=1)
but my problem is
if SELECT id FROM users WHERE type="some" and active=1 doesnt have any result
i want to use
SELECT id FROM users WHERE type="some" limit 0,1
ie the first result
i can do this easly in any language like php/python etc but i just have access to mysql server so cannot do that
but how can i do in pure sql in single query
i tried if statement but not working
Here is one method using ORDER BY:
UPDATE orders o
SET userid = (SELECT u.id
FROM users u
WHERE u.type = 'some'
ORDER BY active DESC
LIMIT 1
);
This assumes that active only takes on the values 0 and 1. If there are other values, use ORDER BY (active = 1) DESC.
Performance should be fine with an index on users(type, active, id).
Another method uses aggregation and COALESCE():
UPDATE orders o
SET userid = (SELECT COALESCE(MAX(CASE WHEN active = 1 THEN u.id END),
MAX(u.id)
)
FROM users u
WHERE u.type = 'some'
);
I would expect the ORDER BY to be a wee bit faster, but sometimes MySQL surprises me with aggregations in correlated subqueries. That said, if you have very few rows for a given type, the performance difference may not be noticeable.

SQL Ordering rows in a select with multiple conditions

I am trying to create an SQL Query to select rows from a database, ordered by a numerical field, however there are repeated entries in the table.
The table consists of the following columns.
UID - Numerical Unique ID
ACCOUNT_NAME - Account Name, unchanged
NICK_NAME - Can be changed by the user at any time
POINTS - Records points held by the user's account
The goal of the query is to display the Account_Name ordered by Points. However, Account_Name is not unique and can appear multiple times in the table.
To deal with this I would like to display only the latest row for each Account_Name.
This meaning that in the results from the select each Account_Name should only appear once. I am trying to have the selection be decided by the UID, meaning that I want only the row with the greatest UID where each account_name appears to be displayed.
I have tried the following without desired results. (The name of the table is ACCOUNT)
SELECT DISTINCT A.account_name , A.uid, A.points
FROM account A, account B
where A.account_name = B.account_name
and A.points > 0
and A.uid >= B.uid
order by A.points DESC;
This doesn't give me the desired results, specifically, there is an account in the database where an outdated row exists with a high value in the Points column. This record appears as the first result in the select, even though it is outdated.
How would you recommend adjusting this Query to select the desired information?
I hope this is enough information to work off of (first time posting a question) Thank you for you help :)
EDIT: Adding in examples with data.
Sample Table Data:
Sample Table Data
Current Results:
Current Results
Desired Results:
Desired Results
Consider joining on an aggregate query calculating MAX(UID)
SELECT a.account_name, a.uid, a.points
FROM account a
INNER JOIN
(
SELECT account_name, MAX(uid) AS max_uid
FROM account
GROUP BY account_name
) agg
ON a.account_name = agg.account_name
AND a.uid = agg.max_uid)
WHERE a.points > 0
ORDER by a.points DESC;
Alternatively, with MySQL 8.0, consider a window function:
SELECT a.account_name, a.uid, a.points
FROM account a
WHERE a.points > 0
AND a.uid = MAX(a.uid) OVER (PARTITION BY a.account_name)
ORDER by a.points DESC;

Query get all latest records based on user_id

I have a table called photos that has hundred of thousands of user uploaded photos.
Each user can obviously upload several photos.
The table schema is:
id,
user_id,
photo,
date_created
I just want to get the latest record that each user_id has posted..
I tried:
SELECT * FROM photos
GROUP BY user_id
ORDER BY date_created desc LIMIT 300
But that is obviously bringing back a lot of strange results.
This seems like an easy query, but I have done hours and hours of research on stack overflow and reading so many different articles on Google, and I can't for the life of me figure this simple query out.
This should get you the latest row for every user:
SELECT p.user_id, photo, date_created FROM photos p
JOIN (
SELECT user_id, MAX(date_created) max_date FROM photos GROUP BY user_id
) max_dates ON p.user_id = max_dates.user_id AND p.date_created = max_dates.max_date
Sample SQL Fiddle
Check this out. I used HAVING MAX(date_created) to retrieve the records which are currently created/uploaded.
SELECT user_id
FROM photos
GROUP BY user_id
HAVING MAX(date_created)
ORDER BY date_created DESC LIMIT 300
I believe what you want is to get rid of that GROUP BY and use a regular 'WHERE user_id = 'something', being the rest correct.
I tried a query like yours and the result was only one record by each 'user_id', lets say. GROUP BY usually uses a WHERE in the sentence...
http://www.w3schools.com/sql/sql_groupby.asp
I hope that helps :) If you get an error, please post it.
select p1.user_id, p1.photo, p1.date_created
from photos p1 left join photos p2
on p1.id < p2.id and p1.user_id = p2.user_id
where p2.id is null
try that
EDIT
forgot table name, my bad. added it in. also, here's a fiddle to see: http://sqlfiddle.com/#!9/a72f6/3

Left join with most recent records before a certain date

I want to select currently active record based on a date. What I need to do is to create a view so a 'select everything' subquery is not going to work.
but right now I can only select one column because it says
Operand should contain 1 column(s)
I could duplicate the select for all the fields I want to get but its going to be performance extensive, plus I have a lot of columns on the history table.
For this simple example (link below), lets say that I need to get the phone number as well.. any idea how I should go about doing it? Thanks.
SQL Fiddler:
http://www.sqlfiddle.com/#!2/1ff7e/1
I think I got it! Seems to work but need more records to try.
SQL Fiddler:
http://www.sqlfiddle.com/#!2/1ff7e/3
Still not working... zzz...I added a few more test data turned out it didn't work!
SQL Fiddler:
http://www.sqlfiddle.com/#!2/360c1/1
My bad. IT IS WORKING! I inserted two duplicate primary keys for the history. Thanks all!!!!
SQL Fiddler:
http://www.sqlfiddle.com/#!2/274c5/1
You can add another subquery to the select clause:
SELECT user.username, user.password,
(SELECT uh.name FROM user_history uh WHERE uh.user_id = user.user_id AND effective_date <= '2013-04-18' ORDER BY effective_date DESC LIMIT 1),
(SELECT uh.phone_number FROM user_history uh WHERE uh.user_id = user.user_id AND effective_date <= '2013-04-18' ORDER BY effective_date DESC LIMIT 1)
FROM user
ORDER BY username;

SQL, Finding Counts of a Group By MAX

Basically, I have a MySQL table with comments, which have IDs and dates submitted, and I want users to be able to edit these comments. When a comment is edited, I'd like to create a new entry in the table with the same ID as the comment being edited, but a new date.
So when I'm selecting my list of comments, I want to use SELECT MAX(DateSubmitted) ... Group By ID, but I'd also like to get a count of the number of IDs that are grouped for each one, so I know how many times a comment has been edited.
I think it should be something like this:
SELECT ID, COUNT(1) as "Number of edits"
FROM comments
GROUP BY ID;
Merged with:
SELECT ID, MAX(`DateSubmitted`), Comment
FROM comments
GROUP BY ID;
If you want to get the latest comment text as well as the date edited and count:
SELECT a.ID, a. MaxDateSubmitted, a.NumComments, b.Comment
(SELECT ID,
MAX(`DateSubmitted`) as "MaxDateSubmitted",
COUNT('ID') as "NumComments"
FROM comments
GROUP BY ID) a
INNER JOIN comments b ON a.ID = b.ID and b.DateSubmitted = a.MaxDateSubmitted;
Note: this assumes no two edits have exactly the same date and time (down to the precision of the time portion). But in this case, I think this is a valid assumption.
If you just want the latest edit date and count:
SELECT ID,
MAX(`DateSubmitted`) as "MaxDateSubmitted",
COUNT('ID') as "NumComments"
FROM comments
GROUP BY ID
SELECT ID, COUNT(ID) as "Number of edits", MAX(`DateSubmitted`)
FROM comments
GROUP BY ID;