MySQL, Select field depending on multiple other rows in table - mysql

I'm implementing a messaging system on my site, and have a table to store the conversation participants like so:
conversation_id user_id
3 2
3 28
4 1
4 2
5 1
5 2
5 28
I can't find a query that will let me check if a conversation already exists between 2 users (or more). I basically want 3 (conversation_id) to be returned if user 2 is sending to user 28, or vice-versa, like that I can keep the conversation going even if they haven't explicitly replied to a previous message.

With the having clause you can filter to only the conversation_ids where both users participate
select conversation_id
from your_table
where user_id in (2, 28)
group by conversation_id
having count(distinct user_id) = 2

Related

How to check if two users have a common chat room?

Currently, I am trying to figure out how to find the common chat rooms between two users by checking their email addresses.
chat_rooms table:
id email chat_room_id
----------------------------------------------
1 johndoe#gmail.com 3
2 janedoe#gmail.com 3
3 test#gmail.com 42
4 check#gmail.com 64
5 janedoe#gmail.com 7
6 test#gmail.com 19
7 johndoe#gmail.com 6
How can I write a MySQL query that can return the common chat_room_id of johndoe#gmail.com and janedoe#gmail.com. Please advise.
You can do this with aggregation:
select chat_room_id
from mytable
where email in ('johndoe#gmail.com', 'janedoe#gmail.com')
group by chat_room_id
having count(*) = 2
This assumes that the same user cannot appear twice in the same room. If that's not the case, then you would just change the having clause to:
having count(distinct email) = 2
Or:
having min(email) <> max(email)

Mysql - select rows which have linked values

Sorry for the bad title, do not know how to describe it in one sentence.
There is the table:
id, user_id, task_id
I need to select user_ids which have records with several task_id
Kind of pseudocode
Select user_id from tasks wherehas task_id = 1 and task_id = 2
As they say, there are many ways to skin a cat. Here is one:
To get a list of users that have multiple tasks assigned, and (at minimum) they have task_id 1 AND task_id 2:
SELECT
user_id
FROM user_tasks // or whatever your table is called
WHERE task_id in (1, 2)
GROUP BY user_id
HAVING COUNT(DISTINCT task_id) = 2
Let us get all the rows where task is is 1 or 2, group them up by user and show only users who have a min task ID that is different to the max task id:
SELECT
user_id
FROM t
WHERE task_id in (1, 2)
GROUP BY user_id
HAVING MIN(task_id) <> MAX(task_id)
You need to appreciate in all of this that when you write a WHERE clause, it is evaluated to be true for every individual row. This means you cannot say WHERE x = 1 AND x = 2 because the value of X can never ever be simultaneously 1 and 2 ON THE SAME ROW.
Instead we use an OR, to get all the user rows that are 1 or 2 and this will give us a mix - some users have multiple rows (the first row is 1 and the next row is 2). Other users have only one row- either a one or a two.
User Task
John 1
Jane 1
Jane 1
Jake 1
Jake 2
Joel 2
When we apply a grouping operation, all those rows are squashed down to one row per user and then things like MIN and MAX can be used and make sense. For a user with only one row his MIN and MAX will be the same number. For a user who had 20 rows that are all value 1, they will also be MIN and MAX the same. Only users who have at least one row that is a 1 and another row that is a 2 will have a different min and max:
User MIN MAX
John 1 1
Jane 1 1
Jake 1 2 <-- the only user HAVING MIN <> MAX
Joel 2 2
Min and max is only really useful in cases where you're looking for 2 different values. In other cases you might look for COUNT DISTINCT that contains the same number as there are elements in the IN list
I think you mean you want the values of user_id for which there is a task with task_id 1 and a task with task_id 2.
Your solution doesn't work because it's looking for a task which has task_id 1 and task_id 2 (which is impossible)
You need:
select a.user_id from tasks a where a.task_id = 1 inner join
tasks b where b.user_id = a.user_id and b.task_id = 2

Sql select where a column has been set atleast once

I have this table
**applications**
id user_id company_id shortlisted
1 10 99 0
2 10 100 1
3 10 101 1
4 10 102 0
5 11 99 1
6 12 99 0
6 12 101 0
What I want is to select all users
which have been shortlisted at-least once
which have not been shortlisted at all
For the first case, i have the following query:
SELECT user_id
from applications
where shortlisted=1
Group
By user_id
and this gives me the expected result like below
**applications**
user_id
10
11
But I'm trying the following query for the second case and it returns me an empty set:
Select user_id
from applications as Application
where shortlisted=0
and NOT EXISTS(Select user_id from applications where user_id=Application.user_id and shortlisted=1)
What am i missing?
PS: Please ignore any typos as i typed them manually for this post.
To get both results in a single query simply use aggregation:
select user_id, max(shortlisted) as was_shortlisted
from applications
group By user_id
You can use group by and having for both.
For the first:
select user_id
from applications
group By user_id
having max(shortlisted) = 1;
For the second:
select user_id
from applications
group By user_id
having max(shortlisted) = 0;
In all honesty, your version with the where is more efficient for the first query. This is just to show how closely related the queries are.
You can try following query;
select user_id from table1
group by user_id having MIN(shortlisted) = 1
This will give you to at least have shortlisted = 1 condition and don't have shortlisted = 0 records.

Grouping notifications by type in MySql

I have the following table structure for notifications table.
id user_id post_id type status date seconduser_id
1 1 23 1 0 somedate 4
2 2 25 2 0 somedate 3
3 3 26 1 0 somedate 4
4 4 28 2 1 somedate 5
5 5 21 2 0 somedate 4
---
---
and so on
Here type = 1 means a like and type = 2 means a comment. status = 0 means seconduser_id hasn't seen the notification yet. seconduser_id is the notification recipient.
Is it possible to get notifications for 1 user (example seconduser_id = 4), with notification grouped by type, showing count and the latest user_id for each type (in one query)?
The implementation of this would be something like User3 and 10 other people liked your post.
Edit: So far I have something that pulls all notification for user 4 and then groups in php. I don't think this is efficient and so am looking for better solutions.
The basic answer is an aggregation query. The complication is getting the latest user id for each type. THere is one method, using substirng_index()/group_concat():
select type, count(*),
substring_index(group_concat(user_id order by id desc), ',', 1) as latest_user
from notifications n
where secondaryuser_id = 4 and status = 0
group by type;
I am not sure if you also want to filter by status.
Edit (added by OP):
Using the above code and grouping by both post_id and type. Because you want to say User1 and 10 others liked your post. Which means for each grouped notification, post_id has to be unique.
SELECT *, substring_index(group_concat(user_id order by id desc), ',', 1) as latest_user, COUNT(post_id) AS total
FROM notifications n
WHERE seconduser_id = 4 and status = 0
GROUP BY post_id, type
Try this:
SELECT MAX(user_id) AS LatestUser, type, COUNT(type) AS total
FROM notifications
WHERE seconduser_id = 4
GROUP BY type

How to count the number of duplicate records in a database?

Consider the following "tweets" table
tweet_id user_id text
-----------------------------------------
1 1 look at my tweet
2 1 look at my tweet
3 1 a very different tweet
4 1 look at my tweet
5 1 look at my tweets
6 2 a cool tweet
7 2 this is my tweet
8 1 hello
9 1 hello
For each user, I want to count the number of duplicate tweets. In the example above, user_id 1 has a total of 5 tweets, of which 2 are unique (tweet_id 3 and 5) and 3 are duplicate (1, 2 and 4). So the outcome of the query for user 1 should be "3".
[EDIT]
Look at user_id 1. The tweet "look at my tweet" appears 3 times, the tweet "hello" 2 times. The total number of duplicate tweets is then 3 + 2 = 5.
For the first part, you can use the following query
select user_id, sum(count)
from
(
select user_id, text, count(tweet_id) count
from tweets
group by
user_id, text
having count(tweet_id) > 1
) t
group by user_id
The inner query finds all users and tweets that have occured more than once. The outer query adds up the duplicate values for each user
Try this:
Select count(text)-count(distinct text) from tweets where user_id=1
select count(*) as count, text from table group by text order by user_id desc;
You will then need a server side function to group by user_id