I'm working on new script. It's something similar to 9gag, there are posts and people like/dislike them and so on.
I have 3 tables for posts, users, like_status
for example:
posts table structure:
postid, postdata , userid, ...
users table stucture:
userid, username , ....
like_status
postid,userid,liked, disliked
I used to use MySQL query
SELECT A.*, B.username FROM posts A, users B WHERE A.userid=B.userid
then I get the like status by assigning the session userid to a variable $SID and use this MySQL query
SELECT * FROM like_status WHERE userid=$SID
everything is working fine, but I'm a little concerned about the server load.
Which is better for server load and memory, to run joining query to be :
SELECT A.*, B.username, C.liked, C.disliked
FROM posts A
JOIN users B ON (A.userid = B.userid)
JOIN like_status C ON (C.userid = $SID)
And what about if I'm using that query to fetch number of posts like 10 posts for example
SELECT A.*, B.username, C.liked, C.disliked
FROM posts A
JOIN users B ON (A.userid = B.userid)
JOIN like_status C ON (C.userid = $SID)
ORDER BY A.postid limit 10
.. Will it cause any performance issues?
That's it.
Best Regards
Related
Ok I am creating a social networking site similar to Instagram. So I want to fetch post from db but only show posts from people the currently logged in user is following just like Instagram. I've tried using a php join and it didn't work, though I think my query is wrong because it's bringing out false results. Please any answer to this would be nice as it would also help others. This is what I've tried to do but don't know where am wrong.
$query = $database->prepare("SELECT n.*, c.*, n.id AS nid, c.id AS cid FROM
newsfeeds n JOIN connections2 c ON c.user1 = n.userId OR c.user2 = n.userId
WHERE n.userId = c.user1 OR n.userId = c.user2 ORDER BY nid DESC");
$query->execute();
I have two table. One is connections2 for users connection and the other is newsfeeds table for post.
This is an image of my db
This one for connections table
this is where all followed people would be
This one for feeds table
This is the post table
Would this query work?
SELECT n.id AS nid,
n.userid,
n.news,
n.news_image,
n.access,
n.date,
c.id AS cid,
c.user1,
c.user2,
c.time,
c.status
FROM newsfeeds n
INNER JOIN connections c ON (c.user1 = n.userid OR c.user2 = n.userid)
ORDER BY n.id DESC;
However, why are you checking the connections table, and why are you checking it for two users? Wouldn't it be easier to check just the newsfeed table for the currently logged in user? Unless is misunderstand your connections table, this could work:
SELECT n.id,
n.userid,
n.news,
n.news_image,
n.access,
n.date,
FROM newsfeeds n
WHERE n.userid = "X"
ORDER BY n.id DESC;
(Replace the "X" with your actual user ID for the currently logged in user)
I'm not too good with explaining things, apologies.
I have 3 tables that are similar to the below:
users
id
username
threads
id
title
user_id
lastpost_id
posts
id
content
thread_id
user_id
On a page listing forum threads, I want the username of both the thread author, and the last post author of that thread to be displayed, I'm attempting to achieve this in a single query.
My query looks like this:
SELECT t.*,u.username FROM threads t
INNER JOIN users u ON t.user_id=u.id
INNER JOIN posts p ON t.lastpost_id=p.id
ORDER BY t.id DESC
The first join enables me to get the username of the user id that started the thread.
The second join is what I'm not sure on, it can get me the user id but how do I get the username from that, as a 3rd join?
You can select the same table multiple times if you give it a different alias. You can give the fields aliases too:
SELECT
t.*,
tu.username as threadusername, /* Result field is called 'threadusername' */
p.*,
pu.username as lastpostusername
FROM threads t
INNER JOIN users tu ON t.user_id=tu.id /* thread user */
INNER JOIN posts p ON t.lastpost_id=p.id
INNER JOIN users pu ON p.user_id=pu.id /* post user */
ORDER BY t.id DESC
You can join to a joined table like this:
SELECT t.*,u.username,u2.username FROM threads t
INNER JOIN users u ON t.user_id=u.id
INNER JOIN posts p ON t.lastpost_id=p.id
INNER JOIN users u2 ON p.user_id=u2.id
ORDER BY t.id DESC
Note, I haven't had time to test it, but it should work (at least in MySQL).
I don't know if I got it correctly, but as per my understanding you can have a inner query to fetch the thread ids and then have a outer query to fetch the posts based on the thread id, have a max on post id and group by user id. Also join to user to have the name. Hope that helps.
I'm having issues writing this query, it's an odd relation that I can't figure out. I'm wondering if it would be better to just use two mysql queries and merge the results with php?... Anyways.. so here we go.
Here's the tables we're using:
- media -
id
userId
accessKey
internalName
type
created
modified
- reposts -
id
userId
mediaId
created
- users -
id
username
Basically, what I want to do is get a result set of media items associated with the user who posted it, and then ALSO, in the same result set, include additional rows for media items that have been reposted, and then for reposted media items, instead of associating the media.userId of the media item for the username association, associate the reposts.userId as the username.
Here's a rough idea to illustrate, these two example queries below need to work as 1 to provide a combined result set.
SELECT media.*, users.username,
0 AS reposted
FROM media
LEFT JOIN users ON users.id = media.userId
SELECT media.id, media.accessKey, media.internalName, media.type, media.modified, users.username, reposts.userId, reposts.created,
1 AS reposted
FROM reposts
LEFT JOIN media ON media.id = reposts.mediaId
LEFT JOIN users ON users.id = reposts.userId
How would I go about doing this? Or would I be better off using 2 queries and merging the results with PHP?
You can use UNION in your query, but UNION requires the same number of columns (and same data type if I recall correctly) on both queries:
(SELECT media.id, media.accessKey, media.internalName, media.type, media.modified, users.username, users.id, media.created,
0 AS reposted
FROM media
LEFT JOIN users ON users.id = media.userId)
UNION
(SELECT media.id, media.accessKey, media.internalName, media.type, media.modified, users.username, reposts.userId, reposts.created,
1 AS reposted
FROM reposts
LEFT JOIN media ON media.id = reposts.mediaId
LEFT JOIN users ON users.id = reposts.userId)
I'm trying to get the users full activity throughout the website.
I need to Join many tables throughout the database, with that condition that it is one user.
What I currently have written is:
SELECT * FROM
comments AS c
JOIN rphotos AS r
ON c.userID = r.userID
AND c.userID = '$defineUserID';
But What it is returning is everything about the user, but it repeats rows.
For instance, for one user he has 6 photos and 5 comments
So I expect the join to return 11 rows.
Instead it returns 30 results like so:
PhotoID = 1;
CommentID = 1;
PhotoID = 1;
CommentID = 2;
PhotoID = 1;
CommentID = 3;
and so on...
What am i doing wrong?
What I'm trying to achieve (example)
If you're a facebook user, every profile has a 'wall' which states the user's activity on the website in chronological order. I'm trying to make something similar.
What am i doing wrong?
you are using one complex query when you could use two simple ones.
You should do it as follows:
SELECT * FROM user AS u
LEFT JOIN rphotos AS r ON u.userId = r.userID
LEFT JOIN comments AS c ON u.userId = c.userID
WHERE u.userId = '$defineUserID'
Updated to fix silly mistakes
What this does is select all relevant users from the user table (1 in this case) then join in the other tables where necessary and shouldnt repeat rows.
The query also makes more sense when you think about it logically.
That you get 30 results if a specific user has 6 photos and 5 comments is quite normal, since you're just fetching the cartesian product of all photos and comments based on user ID. The table structure could shed some light onto possible solutions, but if the comments are related to the photos and you want to fetch all photos and the comments a specific user posted you might use something like :
SELECT * FROM rphotos p
LEFT JOIN comments c on c.photoID = p.photoID
WHERE p.userID = '$defineUserID' OR c.userID = '$defineUserID';
Personally I would split this into 2 queries and display the results separately because mixing them doesn't make any sense to me, ie. use
SELECT * FROM rphotos p
WHERE p.userID = '$defineUserID';
and
SELECT * FROM comments c
WHERE c.userID = '$defineUserID';
edit based on comment
If the ID fields are of the same type you could use something like
select actionID, relatedID, creationDate from
(
select 1 as actionID, photoID as relatedID, creationDate from rphotos
where userID = '$defineUserID'
union
select 2 as actionID, commentID as relatedID, creationDate from comments
where userID = '$defineUserID'
) actions
order by creationDate desc;
The actionID will be 1 for a photo, 2 for a comment and using the relatedID field you could lookup the linked data (if you need it, otherwise you could just drop it from the query).
BTW You probably want to filter the results further (ie. based on date) to prevent joining lots of rows in the union that you won't display...
I'm working on building a forum with kohana. I know there is already good, free, forum software out there, but it's for a family site, so I thought I'd use it as a learning experience. I'm also not using the ORM that is built into Kohana, as I would like to learn more about SQL in the process of building the forum.
For my forum I have 4 main tables:
USERS
TOPICS
POSTS
COMMENTS
TOPICS table: id (auto incremented), topic row.
USERS table: username, email, first and last name and a few other non related rows
POSTS table: id (auto incremented), post-title, post-body, topic-id, user-id, post-date, updated-date, updated-by(which will contain the user-id of the person who made the most recent comment)
COMMENTS table: id (auto incremented), post-id, user-id and comment
On the main forum page I would like to have:
a list of all of the topics
the number of posts for each topic
the last updated post, and who updated it
the most recently updated topic to be on top, most likely an "ORDER BY updated-date"
Here is the query I have so far:
SELECT topics.id AS topic-id,
topics.topic,
post-user.id AS user-id,
CONCAT_WS(' ', post-user.first-name, post-user.last-name) AS name,
recent-post.id AS post-id,
post-num.post-total,
recent-post.title AS post-title,
recent-post.update_date AS updated-date,
recent-post.updated-by AS updated-by
FROM topics
JOIN (SELECT posts.topic-id,
COUNT(*) AS post-total
FROM POSTS
WHERE posts.topic-id = topic-id
GROUP BY posts.topic-id) AS post-num ON topics.id = post-num.topic-id
JOIN (SELECT posts.*
FROM posts
ORDER BY posts.update-date DESC) AS recent-post ON topics.id = recent-post.topic-id
JOIN (SELECT users.*,
posts.user-id
FROM users, posts
WHERE posts.user-id = users.id) as post-user ON recent-post.user_id = post-user.id
GROUP BY topics.id
This query almost works as it will get all of information for topics that have posts. But it doesn't return the topics that don't have any posts.
I'm sure that the query is inefficient and wrong since it makes two sub-selects to the posts table, but it was the only way I could get to the point I'm at.
Dash is not a valid character in SQL identifiers, but you can use "_" instead.
You don't necessarily have to get everything from a single SQL query. In fact, trying to do so makes it harder to code, and also sometimes makes it harder for the SQL optimizer to execute.
It makes no sense to use ORDER BY in a subquery.
Name your primary key columns topic_id, user_id, and so on (instead of "id" in every table), and you won't have to alias them in the select-list.
Here's how I would solve this:
First get the most recent post per topic, with associated user information:
SELECT t.topic_id, t.topic,
u.user_id, CONCAT_WS(' ', u.first_name, u.last_name) AS full_name,
p.post_id, p.title, p.update_date, p.updated_by
FROM topics t
INNER JOIN
(posts p INNER JOIN users u ON (p.updated_by = u.user_id))
ON (t.topic_id = p.topic_id)
LEFT OUTER JOIN posts p2
ON (p.topic_id = p2.topic_id AND p.update_date < p2.update_date)
WHERE p2.post_id IS NULL;
Then get the counts of posts per topic in a separate, simpler query.
SELECT t.topic_id, COUNT(*) AS post_total
FROM topics t LEFT OUTER JOIN posts p USING (topic_id)
GROUP BY t.topic_id;
Merge the two data sets in your application.
to ensure you get results for topics without posts, you'll need to use LEFT JOIN instead of JOIN for the first join between topics and the next table. LEFT JOIN means "always return a result set row for every row in the left table, even if there's no match with the right table."
Gotta go now, but I'll try to look at the efficiency issues later.
This is a very complicated query. You should note that JOIN statements will limit your topics to those that have posts. If a topic does not have a post, a JOIN statement will filter it out.
Try the following query.
SELECT *
FROM
(
SELECT T.Topic,
COUNT(AllTopicPosts.ID) NumberOfPosts,
MAX(IFNULL(MostRecentPost.Post-Title, '') MostRecentPostTitle,
MAX(IFNULL(MostRecentPostUser.UserName, '') MostRecentPostUser
MAX(IFNULL(MostRecentPost.Updated_Date, '') MostRecentPostDate
FROM TOPICS
LEFT JOIN POSTS AllTopicPosts ON AllTopicPosts.Topic_Id = TOPICS.ID
LEFT JOIN
(
SELECT *
FROM Posts P
WHERE P.Topic_id = TOPICS.id
ORDER BY P.Updated_Date DESC
LIMIT 1
) MostRecentPost ON MostRecentPost.Topic_Id = TOPICS.ID
LEFT JOIN USERS MostRecentPostUser ON MostRecentPostUser.ID = MostRecentPost.User_Id
GROUP BY T.Topic
)
ORDER BY MostRecentPostDate DESC
I'd use a left join inside a subquery to pull back the correct topic, and then you can do a little legwork outside of that to get some of the user info.
select
s.topic_id,
s.topic,
u.user_id as last_updated_by_id,
u.user_name as last_updated_by,
s.last_post,
s.post_count
from
(
select
t.id as topic_id,
t.topic,
t.user_id as orig_poster,
max(coalesce(p.post_date, t.post_date)) as last_post,
count(*) as post_count --would be p.post_id if you don't want to count the topic
from
topics t
left join posts p on
t.id = p.topic_id
group by
t.topic_id,
t.topic,
t.user_id
) s
left join posts p on
s.topic_id = p.topic_id
and s.last_post = p.post_date
and s.post_count > 1 --0 if you're using p.post_id up top
inner join users u on
u.id = coalesce(p.user_id, s.orig_poster)
order by
s.last_post desc
This query does introduce coalesce and left join, and they are very good concepts to look into. For two arguments (like used here), you can also use ifnull in MySQL, since it is functionally equivalent.
Keep in mind that that's exclusive to MySQL (if you need to port this code). Other databases have other functions for that (isnull in SQL Server, nvl in Oracle, etc., etc.). I used coalesce so that I could keep this query all ANSI-fied.