I try few mysql statement but didn't come to my expectations.
How to get the total of to_user chat and order by the lowest total?
Let say in this case,
id 7 chat with 2 user
id 6 chat with only 1 user.
so the minimum will be id 6.
Can someone help me with sql statement?
This is what my expected result
count
to_user
1
7
2
6
I think your problem will be solved with the following code:
SELECT COUNT(DISTINCT(from_user)) AS total,to_user
FROM chats
GROUP BY to_user
ORDER BY total ASC
Make sure you index the junction in both directions, otherwise it will BYITA later!
ALTER TABLE messages
ADD INDEX idx_from_to (from_user, to_user),
ADD INDEX idx_to_from (to_user, from_user);
You may want to take into account the fact that the full list of chats for a given user is (from any user, to given user) UNION (to any user, from given user).
Consider user 1 in your sample data, who has sent messages to 5, 6, & 7 but not received any. And user 5 has sent to user 7 and received from user 1.
SELECT COUNT(DISTINCT(from_user)) AS count, to_user
FROM messages
GROUP BY to_user
ORDER BY count ASC
returns the following (which matches the expected result detailed in your question, errors aside)
count
to_user
1
5
1
6
2
7
whereas
SELECT COUNT(*) AS count, from_user AS user
FROM (
SELECT from_user, to_user FROM messages
UNION
SELECT to_user, from_user FROM messages
) t
GROUP BY from_user
ORDER BY count ASC;
returns
count
user
1
6
2
5
2
7
3
1
Related
Please help me with a problem with this SQL in phpmyadmin that finds duplicate records for cleanup:
SELECT userid, MIN(logged_time),`logged_time`, count(email) as duplicated_count
FROM tbl_users
GROUP BY email HAVING count(email) > 1
ORDER BY `duplicated_count` DESC
Here is the GOAL:
Trying to list the duplicate email records in a user database that also tracks when they last used the system under the account.
Trying to identify the records with the oldest logged_time so those duplicates ONLY can be deleted.
PROBLEM:
The SQL above WORKS to identify the duplicates. AND, it WORKS to display the oldest (min) login. BUT>>> The one userID it returns is NOT the user id with the oldest login.
In other words, the data returned is from different records in the duplicate search for the same user email.
The results look like:
userid, MIN(logged_time), logged time,
"111" "2013-04-10 22:35:21", "2017-10-01 04:17:49"
SO...... User "111" is not the one I want to delete! That userid matches the most RECENT logged time. I want the userid for the record that matched MIN(logged_time).
Thanks for the help! I know this may be confusing.
MySQL version is 5.5, so the code posted doesn't seem to work with this version. Any other suggestions?
The one userID it returns is NOT the user id with the oldest login.
Selecting min(logged_time) does not say to only return the oldest login. It just gives you the oldest logged_time for each email.
What you asked for is invalid SQL, but MySQL allows it. It's invalid because it leads to exactly the trouble you're having.
Say we have this.
userid email logged_time
-----------------------------
1 email1 2021-01-01
2 email2 2021-01-01
3 email1 2021-02-01
4 email3 2021-01-01
If we select userid, min(logged_time), count(email) from tbl_users group by email, MySQL can only show you one row per email. For email2 and email3 that's fine, there's only one option. But for email1 it has to choose either 1 or 3.
Normally this would make the query invalid and you would get an error. You can't select a non-aggregated column (userid) which is not in the group by.
But MySQL allows this. It picks a userid at random. And we get the problem you're having.
userid min(logged_time) count(email)
--------------------------------------
2 2021-01-01 1
3 2021-01-01 2
4 2021-01-01 1
See MySQL Handling of GROUP BY for more, and I'd suggest you turn it off with ONLY_FULL_GROUP_BY.
What you're asking for is a bit tricky.
You need to both find emails with duplicates AND pick the oldest row for each email. You can't do all that in a single query, you need two queries joined together.
You know how to find duplicate emails.
-- Note that if you have two entries with the same userid and email
-- it will count that as a duplicate.
select email
from tbl_users
group by email
having count(email) > 1
To order the emails by their logged_time use the row_number window function.
select
userid,
email,
logged_time,
row_number() over(partition by email order by logged_time asc) as login_order
from tbl_users
That will return all the rows with each ranked.
userid email logged_time login_order
--------------------------------------------
1 email1 2021-01-01 1
2 email2 2021-01-01 1
3 email1 2021-02-01 2
4 email3 2021-01-01 1
Join them together and select only where login_order = 1.
-- Get the emails with dups.
with users_with_duplicates as (
select email
from tbl_users
group by email
having count(email) > 1
),
-- Get the logins by email ranked by ascending logged_time
users_in_login_order as (
select
userid,
email,
logged_time,
row_number() over(partition by email order by logged_time asc) as login_order
from tbl_users
)
select
users_in_login_order.*
from users_in_login_order
-- The join will constrain users_in_login_order to only emails with dups
join users_with_duplicates
on users_in_login_order.email = users_with_duplicates.email
where login_order = 1
Try it.
I have a conversation app where users are assigned to conversations.
One conversation can have 1, 2 or more participants, I use a table to link users to conversations :
When user 5 wants to initiate a new conversation with user 6, I don't want to create a new conversation because user 5 and 6 already have an ongoing conversation_id.
They actually also have a different group conversation with user 10
I have 2 parameters : it's user 5 that wants to speak to user 6
How can I query this table to find if a conversation exists only between these 2 users?
I tried this :
SELECT *,count(id) FROM `conversation_members`
WHERE user_id IN (5,6)
GROUP BY `conversation_id`
But
This also returns conversation id 2, while I would like to have
only id 1, so I would like to limit the select query to elements
having a count of 2, If I do the group by before I lose the ability
to match the users.
This also returns id 7 because it matches 1 of the 2 user_ids
it should match both
In the end I just want to retrieve ID 1 as this is the conversation including user 5 and 6 and nobody else. Is this possible only with a Mysql Query?
You can do:
SELECT conversation_id
FROM conversation_members
GROUP BY conversation_id
HAVING SUM(user_id IN (5, 6)) = 2 AND
COUNT(*) = 2;
This will return all conversations (if any) that have exactly those members.
Use the sum of a case expression along with the count in the having clause:
SELECT conversation_id
FROM conversation_members
GROUP BY conversation_id
HAVING SUM(case when user_id IN (5, 6) then 1 end) = 2
AND COUNT(*) = 2;
The ability to use this HAVING SUM(user_id IN (5, 6)) = 2 is not common and is a "MySQL curiosity" I believe. So I suggest you use a case expression instead which I think is also easier to read/understand.
I am trying to get users with their count on notification_template_id.
Means if a user is targeted more than once with the notification_template_id 56.
E.G
user_id notification_template_id count
229 56 3
117 13 2
the query i am trying is:
SELECT
user_id,
notification_template_id,
count(notification_template_id) AS cnt
FROM
user_notifications
GROUP BY
user_id;
but it shows only total count of notifications per user.
the sql is:
SELECT
user_id,
notification_template_id,
count(notification_template_id) AS count
FROM
user_notifications
GROUP BY
user_id,
notification_template_id;
I'm making a newsfeed type of thing and I want to select from multiple tables. The two tables I'll focus on for this question are "posts" and "photos".
Here's my query for just posts:
mysql_query("
SELECT * FROM posts
WHERE toID='$id' AND state='0'
ORDER BY id DESC LIMIT 10");
My posts table has the following column names:
Table: posts
id toID fromID post state date
1 1 1 Aloha 0 1
2 1 1 Hello 0 3
My photos table has the following:
Table: photos
id userID photo state date
1 1 2 0 2
2 1 6 0 4
Expected result:
Aloha
2
Hello
6
Maybe something like:
SELECT *
(SELECT * FROM posts WHERE toID=$id AND state=0) AND
(SELECT * FROM photos WHERE userID=$id AND state=0)
ORDER BY date
When it selects these from the database it should select from where toID and userID are the same. state should equal 0 for both, (0 means visible) and they should be ordered by date. Also I need to create a new variable to pass to my query, so I can then in my php determine which table the information is coming from. Lastly I would like it to group the photos by date, so let's say a user uploaded 20 photos within a 30 minute period, they will only return one row. I use php time() to store my date.
If you want to get all posts and photos together you could use:
SELECT po.*, ph.* FROM posts po
LEFT JOIN photos ph
ON po.toID = ph.userID
WHERE po.state = 0
AND ph.state = 0
ORDER BY po.id DESC, ph.date DESC
I want to display the user with the most posts. the posts are added by counting how many times their username is displayed in the database. How can I grab all the elements and check to see which value appears more then others?
So say my database looks like this:
id | username
1 | test
2 | test
3 | no test
"test" is shown the most, so how could I say
highest poster: "test"
This query returns username and number of occurrences, sorted in reverse order, so the first record is the one with more occurrences:
select username, count(id) from tablename
group by username
order by count(id) desc
UPDATE:
As pointed by thedugas and Joe Phillips, you can add a limit 1 clause to this query to get only the record with the highest number of occurrences
select username, count(id) as uc
from tableName
group by username
order by uc desc
limit 1
SELECT username
FROM mytable
GROUP BY username
ORDER BY COUNT(1) DESC
LIMIT 1