How to find threads only posted by friends? - mysql

So, I have a majority of my SQL query done. However, I can't seem to figure out how select threads that were only posted by the users friends.
Here's my current query that works:
SELECT social_posts.message, social_posts.post_stamp, user.username, user.id, user.default_picture
FROM social_threads
JOIN social_posts ON social_posts.thread_id = social_threads.id
LEFT JOIN user ON user.id = social_threads.user_id
ORDER BY social_threads.id DESC
Here's the friends table:
*----*--------*--------*---------*
| id | user_a | user_b | request |
*----*--------*--------*---------*
| 1 | 3 | 5 | 1 |
*----*--------*--------*---------*
request set to one means the friend request was accepted.
The where clause in the query would have to look something like this:
WHERE ((friends.user_a = '3' || friends.user_b = '3') && friends.request = '1') || (social_threads.user_id = '3')
I just need to figure out how to get that where clause in the main query.
Any help is greatly appreciated.

You would have to Join the friends table, to keep only rows, in which the user is a friend of the thread poster. Something like this:
SELECT social_posts.message, social_posts.post_stamp, user.username, user.id, user.default_picture
FROM social_threads
JOIN social_posts ON social_posts.thread_id = social_threads.id
LEFT JOIN user ON user.id = social_threads.user_id
Join friends on (user.id = friends.user_a and social_threads.user_id = friends.user_b or user.id = friends.user_b and social_threads.user_id = friends.user_a) and friends.request = 1
ORDER BY social_threads.id DESC

use OR and AND operator
WHERE (friends.user_a = '3' OR friends.user_b = '3') AND friends.request = '1'

Related

COnditional JOIN query in MySQL

I have two mysql tables
user:
|--------------------------------|
| id | name | type | ruser_type |
|--------------------------------|
| 1 | Admin | a | |
| 2 | | r | c |
|--------------------------------|
customer
|-------------------------|
| id | name | user_id |
|-------------------------|
| 1 | Sam | 2 |
|-------------------------|
If user.type is 'a' or 's', then its admin user whose name is in user table.
If user.type is 'r' and ruser_type is 'c', then its regular user which has a relation in customer table where customer.user_id = user.id
I want a query which would run a conditional join.
If user.type is 'a' or 's', then name would be fetched from user table.
If user.type is 'r' and and ruser_type is 'c', then name would be fetched from customer table with the JOIN condition customer.user_id = user.id.
For this, I have written a query like this:-
SELECT users.fname as adminFname, customers.fname as customerFname, users.type FROM users
LEFT JOIN customers ON (customers.user_id = users.id AND
(
(users.type = 'r' AND users.ruser_type = 'c')
OR users.type = 'a'
OR users.type = 's'
)
)
WHERE users.id = 1
Is there any possibility to optimize the query more?
Also, how can I write this query using Laravel eloquent?
FWIW, I find this marginally easier to read...
SELECT u.fname adminFname
, c.fname customerFname
, u.type
FROM users u
LEFT
JOIN customers c
ON c.user_id = u.id
WHERE u.id = 1
AND (
(u.type = 'r' AND u.ruser_type = 'c')
OR (u.type IN('a','s'))
)
I have written two sql query hope this will help you
SELECT CASE CU.type WHEN 'a' OR 's' THEN CU.name END AS name,
CASE WHEN CU.type = 'r' AND CU.ruser_type = 'c' THEN CR.name END AS cust_name, CU.type
FROM
user AS CU
LEFT JOIN customer AS CR ON CR.user_id = CU.id
In this you'll get result like this,
name cust_name type
Sam r
Admin a
and i have wrote another query like this,
SELECT CASE WHEN CU.type = 'a' OR 's' THEN CU.name ELSE CR.name END AS name, CU.type
FROM
user AS CU
LEFT JOIN customer AS CR ON CR.user_id = CU.id
In this you'll get result like this
name type
Sam r
Admin a
DB File Link
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=b02d931b68a4f70d8b4a84144c60a572
This will give you required result for all users:
SELECT u.fname adminFname
, c.fname customerFname
, u.type
FROM users u
LEFT JOIN customers c
ON (u.type = 'r' AND u.ruser_type = 'c' AND c.user_id = u.id)
Add where condition as required.
You can even simplify it further to get common firstName column in output:
SELECT COALESCE(u.fname, c.fname) firstName, u.type
FROM users u
LEFT JOIN customers c
ON (u.type = 'r' AND u.ruser_type = 'c' AND c.user_id = u.id)

MySQL: Select newest record from table for every user I talked to

I have 2 tables.
users schema:
private_messages schema:
time_sent is a datetime. All other fields are varchars and ints.
sender_id and receiver_id both refer to id in users.
What I want:
Given a users id, say 1, select the last sent message for every other user (whether the given user sent it or the other user sent it). It should return all the columns of the private_messages table along with the other user's username, and ordered by the time_sent.
The functionality I'm trying to achieve is that of when you open up all of your text messages, and you can see a preview of the last message sent between you and everyone else. This query is killing me because of the fact that the given users id can appear in either the sender_id or the receiver_id. Please help me out with writing the query.
Here is exported sql code to create the tables and their contents (just in case you want something to test with):
users
private_messages
private_messages 2
This should do the trick
SELECT U.username,
U2.username,
IF(PM.sender_id = U.id, 'Sent', 'Received') AS `action`,
PM.message,
PM.time_sent
FROM users U
INNER JOIN private_messages PM ON (PM.sender_id = U.id OR PM.receiver_id = U.id)
INNER JOIN users U2 ON (U2.id = IF(PM.sender_id = U.id, PM.receiver_id, PM.sender_id))
WHERE NOT EXISTS (
SELECT *
FROM private_messages NXT_PM
WHERE NXT_PM.time_sent > PM.time_sent
AND (
( NXT_PM.sender_id = PM.sender_id AND NXT_PM.receiver_id = PM.receiver_id )
OR
( NXT_PM.receiver_id = PM.sender_id AND NXT_PM.sender_id = PM.receiver_id )
)
)
AND U.username = 'Kacy'
ORDER BY time_sent DESC
This returns:
+----------+----------+----------+----------+---------------------+
| username | username | action | message | time_sent |
+----------+----------+----------+----------+---------------------+
| Kacy | liz | Sent | hi again | 2015-03-08 10:47:26 |
| Kacy | Jamie | Sent | hi | 2015-03-07 23:01:18 |
| Kacy | tracy | Received | hi | 2015-03-06 12:04:34 |
+----------+----------+----------+----------+---------------------+
3 rows in set (0.02 sec)
You can do as below technique for getting max per group
select
u1.username as sender,
u2.username as receiver,
m.message,
m.time_sent
from private_messages m
inner join users u1 on u1.id = m.sender_id
inner join users u2 on u2.id = m.receiver_id
left join private_messages m1 on m1.sender_id = m.sender_id
and m1.receiver_id = m.receiver_id
and m1.time_sent > m.time_sent
where m.sender_id = 1
and m1.id is null ;
You can also use
and m1.id > m.id
instead of
and m1.time_sent > m.time_sent
if id is auto-incremented in private_messages table
If you need to see data as both sender and receiver for a given user the condition would be as
where ( m.sender_id = 1 or m.receiver_id = 1 ) and m1.id is null
instead of
where m.sender_id = 1
and m1.id is null ;
http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html

Get conversation and last message Query

i'm tring to get the conversations with the relative last message and order them by time and if is read the message. Let's go to show the my logic.
I created 3 table: inbox_join / inbox_msg / users
On the first table "inbox join" i have the datas about who have a active discussion. In this case we have id_user - "1" and id_user_2 - "4" they have a conversation.
On the inbox_msg table I have the text message, id conversation where the message will shown and other field easy to understand.
Inbox join table
Inbox_msg table
Users table
I made a query that work fine, but the my issue is that i can't have the occured_at on the inbox_msg table. I would like find a better solution for have my desidered result and i can't order how i'm looking for.
This is my query
SELECT DISTINCT (
inbox_join.id_conversation
), user_chat.name AS name_conv, user_chat.surname AS surname_conv, user_chat.username as username_conv, user_chat.id as id_chat, image_upload.name_image, (
SELECT DISTINCT (
message
)
FROM inbox_msg
WHERE inbox_join.id_conversation = inbox_msg.id_conversation
ORDER BY occured_at DESC
LIMIT 1
) AS last_msg, users.name, users.surname
FROM inbox_join
INNER JOIN users ON users.id = inbox_join.id_user
INNER JOIN users AS user_chat ON user_chat.id <> 1 AND (inbox_join.id_user_2 = user_chat.id || inbox_join.id_user = user_chat.id)
INNER JOIN image_upload ON image_upload.id_image = user_chat.profile_image
WHERE inbox_join.id_user = 1
OR inbox_join.id_user_2 = 1
Result desidered selecting the conversation about user 1:
id_conversation | id_user | name | surname | username | last_msg | occured_at_last_msg | read_msg |
1 4 E S E Yes 1380724676 0
4 5 G E K Good 1380724675 0
Query:
SELECT im.id_conversation,
im.id_user,
u.name,
u.surname,
u.username,
im.message AS last_msg,
im.occured_at AS occured_at_last_msg,
im.read_msg
FROM inbox_msg im
JOIN users u
ON u.id_user = im.id_user
JOIN (SELECT id_conversation,
MAX(occured_at) AS occured_at
FROM inbox_msg
GROUP BY id_conversation) im2
ON im2.id_conversation = im.id_conversation
AND im2.occured_at = im.occured_at
ORDER BY im.occured_at DESC
I made this query and should work fine, I would like receive comment about this query.
SELECT DISTINCT (
im.id_conversation
), users.name, users.surname, users.username, image_upload.name_image, im.message as last_msg, im.occured_at, im.read_msg
FROM inbox_join
INNER JOIN (
SELECT sub . *
FROM (
SELECT DISTINCT (
id_conversation
), id_user, message, occured_at, read_msg
FROM inbox_msg
WHERE id_user <> 1
ORDER BY occured_at DESC
) AS sub
GROUP BY sub.id_user
ORDER BY sub.occured_at DESC
) AS im ON im.id_conversation = im.id_conversation
INNER JOIN users ON im.id_user = users.id
INNER JOIN image_upload ON users.profile_image = image_upload.id_image
WHERE inbox_join.id_user = 1 || inbox_join.id_user_2 = 1

How can I select the users which are belonging to group A?

How can I select the users which are belonging to group A?
My tables are below.
my user table.
ID | name |sex
1 | bob |1
2 | kayo |2
3 | ken |1
my fos_group table
ID | name
1 | student
2 | teacher
my fos_user_user_group
user_id | group_id
1 | 1
2 | 2
3 | 1
Bob and Ken are belonging to group_1(student)
Kayo is belonging to group_2(teacher)
ex) I can select 'Bob' from user table like this
$query = $em->createQuery(
"SELECT p.name,p.sex
FROM UserBundle:User p WHERE
p.id = '1' );
But I would like to select the users which belongs to student group(Bob and Ken)
How should I change the sentence in createQuery?
I just guess I need to join the tables though...
additional....
I have tried like this accroding to Fabio's answer
$query = $em->createQuery(
"SELECT p,p.id,p.username,p.userKey
FROM UserBundle:User p
INNER JOIN fos_user_user_group b
ON a.ID = b.user_id
INNER JOIN fos_group c
ON b.group_id = c.ID
WHERE c.group_id = '1'");
$this->data["teachers"] = $query->getResult();
but it says
[Semantical Error] line 0, col 94 near 'fos_user_user_group': Error: Class 'fos_user_user_group' is not defined.
I guess it means I dont have entity for 'fos_user_user_group'.
I have only entity class for Group and User,other tables were created automatically.
In meanwhile,I used like this in other place in $formmapper.
->add('teacher',
null,
array(
'query_builder' =>
function (\Doctrine\ORM\EntityRepository $rep) {
return $rep->
createQueryBuilder('s')
->join('s.groups', 'g')
->where('g.name = :group')->setParameter('group','TeacherGroup');
})
)
it works well,
how can I change this sentence for createQuery()?
I think you can use a INNER JOIN query
SELECT p.name,p.sex
FROM User p
INNER JOIN fos_user_user_group b
ON a.ID = b.user_id
INNER JOIN fos_group c
ON b.group_id = c.ID
WHERE c.group_id = '1'

Can I fire two select statements in a single MySQL command and count resulting rows?

Here's my code as is, working, but very slow:
$graded = R::getAll("SELECT posts.id, posts.discussion, rating.rating, rating.itemid
FROM uv_forum_posts posts
JOIN uv_rating rating ON ( posts.id = rating.itemid )
WHERE posts.discussion = :discussion_id
GROUP BY posts.userid",
array(':discussion_id' => $discussion['id']));
$total = R::getAll("SELECT posts.userid
FROM uv_forum_posts posts
WHERE posts.discussion = :discussion_id
GROUP BY userid",
array(':discussion_id' => $discussion['id']));
$percentages[] = count($graded) / count($total) * 100;
$graded represents all rows that have a rating.
$total represents all user participation, regardless of being graded or not.
I'm only interested in the numerical values of the resulting sets, can I combine these two MySQL calls into a single call that returns two numbers graded and total?
If I correctly understand your requirements you can try
SELECT p.userid,
COUNT(*) total,
COUNT(r.itemid) graded
FROM uv_forum_posts p LEFT JOIN
uv_rating r ON p.id = r.itemid
WHERE p.discussion = :discussion_id
GROUP BY p.userid
Output:
| USERID | TOTAL | GRADED |
---------------------------
| 1 | 8 | 2 |
| 2 | 4 | 4 |
SQLFiddle
UPDATE: If you just want grand total for all posts and users then
SELECT COUNT(*) total,
COUNT(r.itemid) graded
FROM uv_forum_posts p LEFT JOIN
uv_rating r ON p.id = r.itemid
WHERE p.discussion = 1
Output:
| TOTAL | GRADED |
------------------
| 12 | 6 |
SQLFiddle
You could simply use a query as in the format :
Select
( SELECT posts.id, posts.discussion, rating.rating, rating.itemid
FROM uv_forum_posts posts
JOIN uv_rating rating ON ( posts.id = rating.itemid )
WHERE posts.discussion = :discussion_id
GROUP BY posts.userid,
array(':discussion_id' => $discussion['id']))) gradeCount,
(SELECT posts.userid
FROM uv_forum_posts posts
WHERE posts.discussion = :discussion_id
GROUP BY userid,
array(':discussion_id' => $discussion['id'])))totalCount