How to use data from 1st query to check 2nd query? - mysql

Below is my 1st query where I use to get post data and creator data who creates it in post.date_created order from post and account_data_base tables.
SELECT post.*, account_data_base.* FROM post
JOIN account_data_base ON post.creator_id =
account_data_base.user_uid ORDER BY post.date_created DESC
and this is my 2nd query in php after running 1st query which I use to check if the post creator likes his/her post or not.
$stmt = $conn->prepare("SELECT EXISTS(SELECT * FROM like
WHERE post_id = ? and userLike_Id = ?)");
$stmt->bind_param("ss", $postId, $account_data_base_id);
as you can see $postId and $account_data_base_id are values that I get from my 1st query. I wonder is there a way that I can combine 2 queries at once where I can get post data, creator data as well as my 2nd query to check like or not?
Update: this is what I tried but the like check doesn't show accurate info:
SELECT post.*, account_data_base.*,
EXISTS(SELECt * FROM like WHERE like.post_id = post.id and like.userLike_Id = account_data_base.user_uid) FROM post
JOIN account_data_base ON post.creator_id =
account_data_base.user_uid ORDER BY post.date_created DESC

You can use your EXISTS query as subquery in the SELECT clause:
SELECT post.*, a.*, EXISTS (
SELECT * FROM `like` l
WHERE l.post_id = p.id
and l.userLike_Id = a.id
) as likeExists
FROM post p
JOIN account_data_base a ON p.creator_id = a.user_uid
ORDER BY p.date_created DESC
This will add the field likeExists which is either 1 or 0. And you don't need to run the query once per post.

Related

SQL: How to merge two complex queries into one, where the second one needs data from the first one

The goal is to load a list of chats where the user sending the request is a member in. Some of the chats are group chats (more than two members) and there I want to show the profile pictures from the users who wrote the last three messages.
The first query to load meta data like the title and the timestamp of the chat is:
SELECT Chat_Users.ID_Chat, Chats.title, Chats.lastMessageAt
FROM Chat_Users
JOIN Chats ON Chats.ID = Chat_Users.ID_Chat
GROUP BY Chat_Users.ID_Chat
HAVING COUNT(Chat_Users.ID_Chat) = 2
AND MAX(Chat_Users.ID_User = $userID) > 0
ORDER BY Chats.lastMessageAt DESC
LIMIT 20
The query to load the last three profile pictures from one of the chats loaded with the query above is:
SELECT GROUP_CONCAT(innerTable.profilePictures SEPARATOR ', ') AS 'ppUrls',
innerTable.ID_Chat
FROM
(
SELECT Chat_Users.ID_Chat, Users.profilePictureUrl AS profilePictures
FROM Users
JOIN Chat_Users ON Chat_Users.ID_User = Users.ID
JOIN Chat_Messages ON Chat_Messages.ID_Chat = Chat_Users.ID_Chat
WHERE Chat_Users.ID_Chat = $chatID
ORDER BY Chat_Messages.timestamp DESC
LIMIT 3
) innerTable
GROUP BY innerTable.ID_Chat
Both are working separately but I want to merge them together so I don't have to run the second query in a loop due to performance reasons. Unfortunately I have no idea how this can be achieved because the second query needs the $chatID, which it only gets from the first query.
So to clarify the desired result: The list with the profile picture urls (second query) should be just another column in the result of the first query.
I hope it is explained in a reasonably understandable way. Any help would be much appreciated.
Edit: Sample data from the affected tables:
Table "Chats":
Table "Chat_Users":
Table "Chat_Messages":
Table "Users":
This fufils the brief, however it requires a view because MySQL 5.x doesn't support the WITH clause.
It's long and cluncky and I've tried to shorten it but this is as good as I can get, hopefully someone will pop up in the comments with a way to make it shorter!
The view:
CREATE VIEW last_interaction AS
SELECT
id_chat,
id_user,
MAX(timestamp) AS timestamp
FROM chat_messages
GROUP BY id_user, id_chat
The query:
SELECT
Chat_Users.ID_Chat,
Chats.title,
Chats.lastMessageAt,
urls.pps AS profilePictureUrls
FROM Chat_Users
JOIN Chats ON Chats.ID = Chat_Users.ID_Chat
JOIN (
SELECT
lo.id_chat,
GROUP_CONCAT(users.profilePictureUrl) AS pps
FROM last_interaction lo
JOIN users ON users.id = lo.id_user
WHERE (
SELECT COUNT(*) -- the amount of more recent interactions
FROM last_interaction li
WHERE (li.timestamp = lo.timestamp AND li.id_user > lo.id_user)
) < 3
GROUP BY id_chat
) urls ON urls.id_chat = Chats.id
GROUP BY Chat_Users.ID_Chat
HAVING COUNT(Chat_Users.ID_Chat) > 2
AND MAX(Chat_Users.ID_User = $userID)
ORDER BY Chats.lastMessageAt DESC
LIMIT 20

Single SQL to retrieve different information from different tables

I have this query which retrives 10 ( $limited ) queries from MySQL ,
"SELECT content.loc,content.id,content.title,
voting_count.up,voting_count.down
FROM
content,voting_count
WHERE names.id = voting_count.unique_content_id
ORDER BY content.id DESC $limit"
This query did great for posts that were allready in database and had votes , however new posts won't show.
Vote row is "inserted" first time someone votes on post. I guess that the reason why they won't be listed as there is no unique_content_id to connect to.
If i change query into this :
"SELECT content.loc,content.id,content.title
FROM
content
ORDER BY content.id DESC $limit"
it works , but i can't access voting_count.up & voting_count.down rows.
How could i access both information in single query ? Is it doable ?
If some data might not exist in one of the tables, instead of using INNER JOIN you should use LEFT JOIN:
SELECT content.loc,content.id,content.title,
-- USE function COALSESCE will show 0 if there are no
-- related records in table voting_count
COALESCE(voting_count.up, 0) as votes_up,
COALSESCE(voting_count.down, 0) as voted_down
FROM content LEFT JOIN voting_count
ON content.id = voting_count.unique_content_id
ORDER BY content.id DESC
As someone else above mentioned, what is names.id? However, perhaps the following might be of use assuming the join should have been from content.id to voting_count.unique_content_id:
$sql="select
c.`loc`,c.`id`, c.`title`,
case
when v.`up` is null then
0
else
v.`up`
end as 'up',
case
when v.`down` is null then
0
else
v.`down`
end as 'down'
from `content` c
left outer join `voting_count` v on v.`unique_content_id`=c.`id`
order by c.`id` desc {$limit}";

mysql: subquery with returned many row

I have this query for load user stream in my app , is it too hard if we have 10000 matched row in 'follow' ?
SELECT *
FROM post
WHERE user_id
IN (SELECT follow_id
FROM follow
WHERE id='$some_id')
AND type='accepted'
ORDER BY id DESC LIMIT $page , 20
Syntactically your code looks correct.. I don't see any errors so then if you're talking about efficiency I would join the tables and include the second filter on the JOIN
SELECT p.*
FROM post p
JOIN follow f
ON f.follow_id = p.user_id
AND f.id = '$some_id'
WHERE p.type = 'accepted'
ORDER BY p.id DESC LIMIT $page , 20
MySQL handles large sets of data a lot better through a join than with an IN()...
Think of it this way.. because the IN() can have pretty much anything inside of it, MySQL has to check it with everything returned for each row... instead of checking once when you JOIN..
With that many returning, I have a feeling a Join might be more efficient
SELECT *
FROM post p Join
follow f On p.user_id = f.follow_id
WHERE f.id='$some_id'
AND p.type='accepted'
ORDER BY p.id DESC LIMIT $page , 20

How to cope up with "your subquery return more than one row"

Below is my query,
select * from user_details
where
user_id in (
select sender_id from pending_friend_request_table
where receiver_id=10
)
Now I'm getting an obvious error that 'your subquery returns more than 1 row'.
My question is, is there any way through which I can make the above query to work by using some MySQL keywords/functions like range, limit, exists etc or through some other methods.
Better to go with JOINS
SELECT * FROM user_details AS u
LEFT JOIN pending_friend_request_table AS p
ON (u.user_id = p.sender_id)
WHERE p.receiver_id = 10;

mysql join - select col1 where col2 matches a (filtered) col in other table

Here's what I want to do:
select tableB.column1 WHERE tableB.column2 = some_var
select tableA.column1 WHERE tableA.column2 was a result from step one.
Can this be done in one select? What's the best way to do this, especially performance-wise? I'm using PHP.
EDIT:
I have a conversation based messaging system. 1 convo table and 1 replies table. Replies table includes columns: responder and convo_id. To load convo I get all replies with that convo_id.
I want to use the convoId to get all responders to that convo, and go into usertable and select all the avatars of responders, then store the avatars in array and echo them out as needed.
Try the following:
select a.Column1
FROM tableA a
LEFT JOIN tableB b ON a.Column2 = b.Column1
You could also use subquery, but that's less performant.
You may want to try the following sql statement
SELECT u.avatar
FROM usertable u
JOIN replies r ON u.responder_id = r.responder_id
WHERE r.convo_id = 1234
this will get all the avatars of the users who participated in the conversation with id 1234
Here's what I decided to go with. It builds an array ($avatars) where keys are usernames and values are avatars.
$result = mysql_query("SELECT
DISTINCT users.avatar,replies.sender
FROM users
JOIN replies
ON users.username = replies.sender
WHERE replies.convo_id = '$convoID'
");
while($array = mysql_fetch_assoc($result)){
$avatars[$array['sender']] = $array['avatar'];
}