I have the following database table below
I want to display notification to the user with owner_id 1. The notification show tell the owner that two users (with ids 17 and 2) commented on his/her post with post_id 1.
I've tried the following query but it returns 2 rows instead. How can I can structure the query to return one row, because I want the notifications for one post to be returned together? Thank you.
SELECT DISTINCT commenters_id, id, owner_id,
post_id, type, UNIX_TIMESTAMP(date_done) AS date
FROM notification
GROUP BY commenters_id
HAVING owner_id = '$user_id' AND commenters_id != '$user_id'
ORDER BY date_done DESC
This code will not give you the commenters_id, but instead a count of how many people have replied to each post. The date will be the last time someone replied to that specific post:
SELECT
COUNT(DISTINCT commenters_id) AS commenter_count,
owner_id,
post_id,
type,
UNIX_TIMESTAMP(MAX(date_done)) AS date
FROM notification
WHERE owner_id = '$user_id' AND commenters_id != '$user_id'
GROUP BY owner_id, post_id, type
ORDER BY UNIX_TIMESTAMP(MAX(date_done)) DESC
You can use GROUP_CONCAT(commenters_id) to get a comma-separated list of commenter IDs for the post. But then you have to group by post rather than commentor, so the query would look something like:
SELECT DISTINCT GROUP_CONCAT(commenters_id), id, owner_id,
post_id, type, UNIX_TIMESTAMP(date_done) AS date
FROM notification
GROUP BY post_id
HAVING owner_id = '$user_id' AND commenters_id != '$user_id'
ORDER BY date_done DESC
GROUP_CONCAT allows some processing of the data if you need it, like returning only distinct values or sorting the values. See the full documentation here: http://dev.mysql.com/doc/refman/5.5/en/group-by-functions.html#function_group-concat
your problem is that you select the date_done column, too, which makes the rows unique.
Neither DISTINCT nor GROUP BY are allowed to group the result set under this circumstances.
Leave the column out of this query or use something like MAX(date_done)
EDIT:
wait...you already get only two rows, not four ? Isn't that the result that you wanted? maybe I missunderstood the question
Related
So I have two tables that displays values like a Facebook look-a-like feed. They both have a datetime column named date, but I want them to order them together by date DESC.
I think join is the correct way(?), but not quite sure. Can someone help me out?
Currently I have them in two different queries:
$status1 = "1";
$stmt1 = $link->prepare('
SELECT id
, ident_1
, ident_2
, date
, ident_1_points
, ident_2_points
FROM duel
WHERE active=?
ORDER
BY date
');
$stmt1-> bind_param('s', $status1);
and
$status2 = "OK";
$stmt2 = $link->prepare('SELECT id, ident, pp, date FROM sales WHERE status=? AND team IN (2, 3) ORDER BY date DESC LIMIT 20');
$stmt2->bind_param('s', $status2);
How should I do this?
If you want one continuous list containing data from both tables, and the whole thing ordered by date overall, then you might need a UNION query in a subquery, and then order the outer query, something like this:
SELECT *
FROM
(
SELECT id, ident_1, ident_2, date, ident_1_points, ident_2_points
FROM duel
WHERE active=?
UNION ALL
SELECT id, ident, pp, date, NULL, NULL
FROM sales
WHERE status=?
AND team IN (2, 3)
LIMIT 20
) list
ORDER BY date DESC
The requirement isn't 100% clear to be honest from your description (sample data and expected results always helps when asking SQL questions), but I think this is pretty close to what you need.
JOIN doesn't seem appropriate, unless you want a result set where items from each table are linked to each other by some common field, and you combine them such that you get all the columns side by side, showing the data from one table next to the data which matches from the other table.
If you're unsure, I suggest looking at tutorials / examples / documentation which show what JOIN does, and what UNION does.
I have two tables (users and posts) and I want to write out all posts (among other things) by one user. I'm thinking I should use a JOIN and WHERE but I get an error for using WHERE.
This is my code:
SELECT username, post, joinDate, title, info FROM users
WHERE userId='18'
JOIN posts ON users.userId=posts.userId
ORDER BY date DESC
I'm new to this and perhaps there is a better way but I can't figure it out atm.
Thankful for all answers!
The JOIN clause comes before the WHERE clause, after the FROM clause. First you join together all the tables you need, then you do your filtering with WHERE. Like this:
SELECT username, post, joinDate, title, info
FROM users
JOIN posts ON users.userId=posts.userId
WHERE users.userId='18'
ORDER BY date DESC
try like below
SELECT u.*,p.*
FROM users u JOIN posts p ON u.userId=p.userId
WHERE u.userId=18
ORDER BY date DESC
where will be after join and 18 is int datatype value so not need single quote for this and use alias for avoiding ambigous column name
SELECT username, post, joinDate, title, info
FROM users
JOIN posts ON users.userId=posts.userId and users.userId='18'
ORDER BY date DESC
if userId is in users table then YES you can use where userId='18'.
If userId is in posts table then it should be userId='18' be in join part.
I have a table which has 2 numeric (int) values (IDs) as sender_id and receiver_id.
What I'm trying to do is group these rows as "conversations". the conversation between :
sender_id = 1, and receiver_id = 5,
is the same conversation where sender_id = 5 and receiver_id = 1
So when I fetch the database rows, I want to have only 1 row for each conversation.
I will fetch these conversation for a specific user. the user ID (which I already know and will refer to as userId) can be in sender_id and receiver_id.
So my algorithm would be something like:
Select All rows
from Database,
where sender_id = userId OR receiver_id = userId,
group by sender_id+user_id
the result rows have to include the other column value (not the one equal to userId), it can include both though and I will have to detect the other one by comparing them both to the userId I have.
To be honest I have always been uncomfortable with SQL manual. For some reason I'm failing to find what I need from there. Forgive me..
I'm not sure if I should make a temp table or use the SQL SUM function, or if I can use something like GROUP BY sender_id+receiver_id
More info (not sure if relevant):
I'm using php
The table has few more columns like record_id, create_date and read_date
Your help and replies are greatly appreciated.
Update:
The solution to my question is marked below. However, I encountered another problem that I thought of sharing, as it can maybe potentially help someone viewing this question later.
The problem I faced is, when I show the conversations, I wanna show the last message row. Now when grouping is done, the grouping stacks on the first row found. and I want the opposite. I want the rows returned to contain the last message row per conversation.
I could do that with the following query. Please note that this is only one way of doing it and I'm not yet sure of the performance of this query. I will test it later and update this if needed.
the $this->id is the id of the user I wanna display the conversations for.
"SELECT t1.* FROM table t1
INNER JOIN (
SELECT sender_id, receiver_id, max(create_date) lastCreateDate
FROM table
WHERE receiver_id = ".$this->id." OR sender_Id = ".$this->id."
GROUP BY GREATEST(sender_id ,receiver_id), LEAST(sender_id,receiver_id)
) t2
ON ((t1.sender_id = t2.sender_id
OR t1.sender_id = t2.receiver_id)
AND t1.create_date = t2.lastCreateDate)
ORDER BY create_date DESC LIMIT 0,15"
LEAST returns the lowest and GREATEST the greatest value:
GROUP BY LEAST(sender_id, receiver_id), GREATEST(sender_id, receiver_id)
GROUP BY max(sender_id, receiver_id), min(sender_id, receiver_id)
I'm putting together a simple forum script with topics/posts. I'm trying to order topics by latest post and I've had some luck with the answer in the following question: MYSQL Order from another Table, but the problem I have is that some topics don't have any posts yet, so the query doesn't select those topics at all.
Current coding is:
SELECT DISTINCT forum.*
FROM forum
INNER JOIN forum_posts
ON forum.id = forum_posts.parent_id
GROUP BY forum.id
ORDER BY forum_posts.parent_id DESC,
forum_posts.time_created DESC
LIMIT ?,?
I want to tell the ORDER BY to order by forum.time_created if there are no matches in forum_posts.parent_id for a topic.
On a side note, I would also like to know how to put a WHERE clause into this query as well. I want to only get rows from forum table "WHERE access <= ?", but can't work out where to put that snippet in.
Any help much appreciated!
EDIT:
Target is to return topics (from forum table)
According to following details:
WHERE forum.access <= ?
LIMIT ?,?
ORDER BY
Latest Post From forum_posts table with forum_posts.parent_id matching on forum.id,
or forum.time_created
EDIT 2:
An example SQLfiddle with relevant data. This doesn't work as the order should really come out as 11,10,9,1,2
http://sqlfiddle.com/#!2/83535/2
Have a look at this: http://sqlfiddle.com/#!2/be909/1
Here's my final query:
SELECT forum.*, recent_forum_posts.time_created as latest_post
FROM forum
LEFT JOIN (SELECT MAX(forum_posts.time_created) as time_created, forum_posts.parent_id
FROM forum_posts
GROUP BY forum_posts.parent_id) AS recent_forum_posts
ON forum.id = recent_forum_posts.parent_id
WHERE forum.access > 2
ORDER BY recent_forum_posts.time_created IS NULL DESC,
recent_forum_posts.time_created DESC,
forum.time_created DESC
LIMIT 5
Essentially, the subquery (the bit in brackets after LEFT JOIN) selects the most recent post for each parent_id from the forum_posts table.
That is then LEFT JOINed (as we want to list all forum's even if there are no posts yet).
I have a table that contains articles posted by users. The structure of the table is like this:
id uid author article_name article num_views edit_time
id is the article id, uid is the author id and num_views is how many times this article is being viewed.
What I need is to display ONLY the most viewed article according to uid
In short , if uid is author id and article id is 5 , what I need is to display something like :
id uid article_name num_views
5 1 article title 100
I tried to run several queries in Mysql but i could not figure it out , can anyone help please ??
The most viewed article and its count by each user:
SELECT `id`, `uid`, `article_name`, `num_views`
FROM `table`
WHERE `num_views` IN (
SELECT MAX(`num_views`) FROM table GROUP BY `uid`)
For only given uid
SELECT `id`, `article_name`, MAX(`num_views`)
FROM `table`
WHERE `uid` = <user id>
If you need only one entry you should try to sort your query with ORDER BY command and limit it to the one article by LIMIT 1 command.
SELECT * FROM ARTICLES WHERE (some criteria) ORDER BY NUM_VIEWS DESC LIMIT 1.
That should select an article with the most views.
It's a bit hacky and if your table gets big it's going to be non-performant, but one way to do this would be:
select uid,
group_concat(id order by num_views desc) as most_viewed_id,
group_concat(article_name order by num_views desc) as most_viewed_name,
group_concat(num_views order by num_views desc) as num_views
from yourtable group by uid
You'll then have to parse out the first element from each of the group_concat'd fields.
Another way would be to use a join with a subquery, but it can be weird if there's two articles for the same user with the same highest number of views, and also has performance issues:
select uid,num_views,id,article,article_name from
yourtable join
(select uid,max(num_views) as maxviews from yourtable group by uid) as subtable
using (uid,num_views)
Of course at a certain point the best way might be to just iterate over uids with a simple order by query. It's a lot more queries but it can be faster depending on your data. Unfortunately SQL just isn't really set up to do queries like this.