I have two tables, one for the posts and another for the users. I am fetching all posts from the 'posts' table and user data (who posted that post) from the tbl_users.
currently, I am using this query :
$query = $pdo->prepare("SELECT * FROM `posts`,`tbl_users` WHERE id = user_id_p ORDER BY `post_id` DESC");
$query->execute();
return $query->fetchAll();
it is working fine, it is fetching all the posts from the posts table and user data from tbl_users.
However, my issue is this that I don't want to fetch all posts, but I want to fetch only those posts which are posted by the specific user(for example by John only) and the user data for John only from the tbl_user.
(field Id from tbl_users and field user_id_p from the table posts are same in both the tables.)
Any suggestions or help?
Although your query is working, it is not at all efficient because it uses an implicit cross join which results in a very large resultset.
Use a proper INNER JOIN with a condition applied with WHERE:
SELECT u.*, p.*
FROM tbl_users u INNER JOIN posts p
ON u.id = p.user_id_p
WHERE u.id = ?
ORDER BY p.post_id DESC
Replace ? with the id of the user.
You can use JOIN for this. Example
select P.name, U.name from post P NATURAL JOIN user U;
I cannot get multiple rows of the Posts.body column to show up in the subquery. I DO want subqueries and I haven't figured out a way around this MySQL restraint. Please let me know if you need more information.
SELECT profile_picture, body, post_date, filename, username FROM Posts, Users
WHERE Posts.IDUser = Users.IDUser
AND Posts.body LIKE (SELECT Posts.body FROM Posts WHERE Posts.IDUser = (SELECT Users.IDUser FROM Users WHERE Users.username = 'noah'))
ORDER BY `Posts`.`post_date` DESC;
It's not really clear what the problem is exactly, but from what I can see it seems you need to use IN instead of LIKE:
SELECT profile_picture, body, post_date, filename, username FROM Posts, Users
WHERE Posts.IDUser = Users.IDUser
AND Posts.body IN (SELECT Posts.body FROM Posts WHERE Posts.IDUser = (SELECT Users.IDUser FROM Users WHERE Users.username = 'noah'))
^^ here
ORDER BY `Posts`.`post_date` DESC;
On the other hand the inner SELECTs seem unnecessary as you are already joining Posts and Users so you can probably simplify it a lot using just a join.
What exactly are you trying to select?
Any time you are joining a table to itself, or using it in a subquery, you have to alias it.
So your inner query should be something like
(
SELECT p.body
FROM Posts p
WHERE p.IDUser = something
)
I find it pretty hard to understand what you're trying to do with this query. I have a feeling it could be greatly simplified but I'm not sure what data you are after.
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.
I basically have three tables, posts, images and postimages (this simply contains the ids of both the other tables and allows more than one image in each post and each image to be reused in multiple posts if necessary).
I'm trying to list the titles of all the posts, along with a single, small image from each (if one exists)
I can do it with the following:
$sql ="SELECT * FROM posts p, images im, postimages pi WHERE
AND pi.post_id = p.id
AND pi.image_id = im.image_id
ORDER BY created_at LIMIT 10";
But obviously, if there is more than one image, the record is displayed twice.
I know I could probably do it with a subquery, but that seems horribly inefficient. Is there a more elegant way around this?
Any advice would be appreciated. Thanks.
select
*
from
posts p
left outer join (select post_id, max(image_id) as image_id
from postimages group by post_id) pi on
p.id = pi.post_id
left outer join images im on
pi.image_id = im.image_id
You can do the subquery so that it only has to be executed once, not per row. This way, it's used as a subquery for an entire table, and then joined to the posts. Obviously, this can be MIN(image_id) if you want to take the first image. Really, whatever you prefer.
Edit: Made it be a left outer join to capture even those images that don't exist in the posts. This will return null for the image in the case that it happens to be non-existant.
SELECT p.id,p.title,im.src
FROM posts p
LEFT JOIN postimages pi
ON p.id = pi.post_id
LEFT JOIN images im
ON pi.image_id = im.image_id
GROUP BY p.id
ORDER BY created_at
LIMIT 10
Not sure if this is the most efficient, you will have to run this against a inner query.
It will work only for MySql as far as I know.
i am trying to develop a site where users can become friends of each other and can see their posts after the date the became friends........i have already posted this question about 5-7 days but could not find any solution........!!
so...
i have two tables..........
posts and friends
and my query is
$sql = mysql_query("
SELECT *
FROM posts p
JOIN friends f
ON p.currentuserid = f.friendid
AND p.time >= f.friend_since
OR s.currentuserid=$myid
WHERE f.myid=$thisid
ORDER BY p.postid DESC LIMIT 20");
where $myid is currentuserid and p.currentuserid is the name of cell in poss table and friendid is in friends table.
this query is working all the way right but problem is that in this query if current user post any thing it displays two times i.e
my new post
mynew post
but in database it is single entry.....!! but current user can see their friends posts for single time
how can i solve this problem
this query is working all the way right but problem is that in this query if current user post any thing it displays two times
Use:
SELECT DISTINCT *
FROM posts p
JOIN friends f ON p.currentuserid = f.friendid
AND p.time >= f.friend_since
OR s.currentuserid=$myid
WHERE f.myid=$thisid
ORDER BY p.postid DESC
LIMIT 20
I added the DISTINCT keyword in order to remove duplicates. Usually I'd use a GROUP BY instead, but you didn't supply the columns.