SQL, Finding Counts of a Group By MAX - mysql

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;

Related

how to restrict SQL Left JOIN to only return the latest record of the secondary table

I have two tables (documents and states).
documents fields:
id, (int)
document,(string)
file, (string)
creation (date)
states fields:
id, (int)
id_document, (int)
status, (string)
last_update (date)
id_document obviously match id in the first table.
The first table holds data related to documents and the second an updated serie of states of the processing of documents of the first table.
I need to create a view to show the list of documents with, only, their last reached status, if any.
I wrote this query but that make the correct join but I'm unable to restrict it to the last status:
SELECT
documents.*, states.status, states.last_update
FROM
documents
LEFT JOIN states ON states.id = documents.id
ORDER BY states.last_update
I tried with DISTINCT, DISTINCTROW but without luck....
This should provide what you are looking for (there may exist a more elegant solution):
select d.*,
s.status,
s.last_update
from documents d,
states s
where s.id = d.id
and s.last_update = ( select last_update
from states
where id = d.id
order by last_update desc
limit 0,1 )
or s.last_update is NULL;
Use a sub-query with max(last_status) per document. Then inner join the sub-query to your query on document and last_status.
Maybe this works:
SELECT
documents.*, updates .status, updates.updated
FROM
documents
LEFT JOIN (SELECT id_document, status, MAX(last_update) AS updated
FROM states
GROUP BY id_document) AS updates
ON states.id = documents.id
ORDER BY states.last_update

use COUNT(*) values from one table to another

Suppose I have two tables, users and posts. Posts has the following fields, userid, postid, etc and userid can appear multiple times as one user can write multiple posts....I'm just trying sort the users table based off the # of occurrences per userid in the posts table. I can get the # of occurrences per user using this
SELECT userid, COUNT(*)
FROM posts
GROUP BY userid;
I would like to use the values under COUNT(*) column, maybe add it to my other table because then I can simply to something like this
SELECT * FROM users
ORDER BY newcolumn ASC;
but I'm having trouble doing that. Or can I do it without having to add an extra column? Hints please. Thanks
Left join is the key here!
SELECT users.userid,count(posts.userid) AS total_count
FROM users
LEFT JOIN posts on posts.userid = users.userid
GROUP BY users.userid
ORDER BY total_count DESC;
We are taking the left join on two tables with same user_id and we are counting the total number of posts per user using group by. Finally sort by count and show results.
try an left join:
select users.userid, [user fields],count(postid) as posts_count
from users
left join posts on posts.userid = users.userid
group by users.userid,[user fields]
order by posts_count desc.
You want to select users (FROM users) but you want to sort based on criteria in another table (COUNT(*) FROM posts) -- therefore you need to use a JOIN
Off-hand I can't seem to recall if "JOIN" or "RIGHT JOIN" or "FULL JOIN" is what you need if you wanted to get a cartesian product of the tables then group and aggregate on a single field, but I can avoid the need to remember with a subquery (hopefully someone will soon post a smaller and smarter answer):
SELECT users.* FROM users
JOIN (
SELECT userid, COUNT(*) as count
FROM posts
GROUP BY userid
) as subquery ON users.id = subquery.userid
ORDER BY subquery.count
Note: I haven't tested this query, but it looks good to me. Again: hopefully someone will post a better answer soon as I'm not doing my due dilligence, but you definitely need a JOIN :)
You could add a post_count column to the users table, but you would also have to update that count column every time a user creates a new post and you would have to build that logic into your application.
Otherwise, it looks like the answer from FallAndLearn will get you what you need.

Merging 3 Tables, Limiting 1 Table With Multiple Fields Needed

Been looking into this for awhile. Hoping someone might be able to provide some insight. I have 3 tables. All of which I'm grabbing multiple columns, but the 3rd I need to limit the output to just the most recent timestamp entry, BUT still display multiple columns.
If I have the following data [ Please see SQL Fiddle ]:
http://sqlfiddle.com/#!2/84b91/6
The fiddle is a list of (names) in Table1(users), (job_name,years) in Table2(job), and then (score, timestamp) in Table3(job_details). All linked together by the users id.
I am definitely not great at MYSQL. I know I'm missing something.. possibly a series of JOINs. I have been able to get Table 1, Table 2 and one column of Table 3 by doing this:
select a.id, a.name, b.job_name, b.years,
(select c.timestamp
from job_details as c
where c.user_id = a.id
order by c.timestamp desc limit 1) score
from users a, job as b where a.id = b.user_id;
At this point, I can get multiple column data on the first two columns, limit the 3rd to one value and sort that value on the last timestamp...
My question is: How does one go about adding a second column to the limit? In the example in the fiddle, I'd like to add the score as well as the timestamp to the output.
I'd like the output to be:
NAME, JOB, YEARS, SCORE, TIMESTAMP. The last two columns would only be the last entry in job_details sorted by the most recent TIMESTAMP.
Please let me know if more information is required! Thank you for your time!
T
Try this:
select a.id, a.name, b.job_name, b.years, c.timestamp, c.score
from users a
INNER JOIN job as b ON a.id = b.user_id
INNER JOIN (SELECT jd.user_id, jd.timestamp, jd.score
FROM job_details as jd
INNER JOIN (select user_id, MAX(timestamp) as tstamp
from job_details
GROUP BY user_id) as max_ts ON jd.user_id = max_ts.user_id
AND jd.timestamp = max_ts.tstamp
) as c ON a.id = c.user_id
;

Combine search from 2 rows in mysql

I run a survey where all answers are stored in a separate row in the 'survey' table.
My table looks like this:
(ID,user_id,Q,A)
(1,10,'laundry','oxiclean')
(2,10,'laundry','tide')
(3,10,'laundry','pods')
(4,11,'laundry','spray n wash')
(5,11,'laundry','resolve')
(6,12,'laundry','oxiclean')
(7,13,'laundry','oxiclean')
I now need to pull the count of user id that selected ONLY specific products.
"SELECT *, count(user_id) FROM survey WHERE Q='laundry' GROUP BY a"
the above will give a an overall COUNT but I need to get my count based on users that selected ONLY 'oxiclean' for example. This should return 2.
Or users that selected 'oxiclean' AND 'tide' ONLY.
How do I go about performing this 'combination' of results pulled from different rows?
Thanks a lot!
select user_id from survey group by user_id having count(user_id) = 1
This retrieves a list of users which have only one answer in the survey. Use it as a filter condition:
select q,a,count(user_id)
from survey
where a = 'oxiclean'
and user_id in (select user_id from survey group by user_id having count(user_id) = 1)
You can achieve that using a subquery, for your case it will be something like that :
SELECT *, COUNT(user_id)
FROM survey AS s
WHERE Q = 'laundry'
AND A = 'oxiclean'
AND user_id NOT IN (SELECT user_id FROM survey WHERE Q = s.Q AND A != s.A);
s.Q and s.A refer to the parent field so you don't have to reinject the name a second time.
Downside : the query works only if you want one specific answer.
If you want one query to retrieve the overall count, this one should do the trick :
SELECT A, COUNT(user_id)
FROM (
SELECT A, user_id
FROM survey
WHERE Q='laundry'
GROUP BY user_id
HAVING COUNT(user_id) = 1
) AS t
GROUP BY A
Downside : the query give only answers who have only at least one unique user_id as seen here, and this syntax create a temporary table which is something to avoid for performance reasons.

MySQL get row closest to NOW()

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.