SQL Multiple Row Subquery Issue - php

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.

Related

SQL: How do I filter (WHERE) a joined (ON) table in SQL?

I have two tables (users and posts) and I want to write out all posts (among other things) by one user. I'm thinking I should use a JOIN and WHERE but I get an error for using WHERE.
This is my code:
SELECT username, post, joinDate, title, info FROM users
WHERE userId='18'
JOIN posts ON users.userId=posts.userId
ORDER BY date DESC
I'm new to this and perhaps there is a better way but I can't figure it out atm.
Thankful for all answers!
The JOIN clause comes before the WHERE clause, after the FROM clause. First you join together all the tables you need, then you do your filtering with WHERE. Like this:
SELECT username, post, joinDate, title, info
FROM users
JOIN posts ON users.userId=posts.userId
WHERE users.userId='18'
ORDER BY date DESC
try like below
SELECT u.*,p.*
FROM users u JOIN posts p ON u.userId=p.userId
WHERE u.userId=18
ORDER BY date DESC
where will be after join and 18 is int datatype value so not need single quote for this and use alias for avoiding ambigous column name
SELECT username, post, joinDate, title, info
FROM users
JOIN posts ON users.userId=posts.userId and users.userId='18'
ORDER BY date DESC
if userId is in users table then YES you can use where userId='18'.
If userId is in posts table then it should be userId='18' be in join part.

SQL statement for getting multiple photos for post

I have a query that gets posts and posts with photos from a user and user's that he follows. This is the query below.
$query = "SELECT Posts.*, Profiles.ProfilePhoto, Users.Name, Users.Username, Post_Photos.Photo
FROM (((Posts
INNER JOIN Profiles ON Posts.UserID = Profiles.UserID)
INNER JOIN Users ON Posts.UserID = Users.ID)
INNER JOIN Post_Photos ON Posts.ID = Post_Photos.PostID)
WHERE (Posts.UserID = ? OR Posts.UserID in (SELECT Followed FROM Follow WHERE Follower = ?))
GROUP BY PostID
ORDER BY Posts.CreateDate DESC";
This query will compile and although it gets the results i need there is some bugs.
There first is that with this query it will only return results where Post_Photos.Photos is true. So the posts that don't have photos are not being returned. I played around with GROUP BY thinking that could work but I could not come to any solution. Is there something I am missing that could still return results from Posts Table without having a value in Post_Photos?
And the second issue is that if there are multiple photos assigned to a postID in my Post_Photos table it creates a post for each photo. To fix that I added a GROUP BY PostID to my query but then only one image will show up.
$photo = $row['Photo']; // getting photo from table
I played around with a foreach, while loop with $row['Photo'], and tried to make an array but I could not get them to return the photos and then print them to my $output. Any clue on how to fix the issue within my query or if theres a more proper way to get that data would be very helpful!
To resolve the first issue, you need to change the INNER JOIN on Post_Photos to a LEFT JOIN. That will ensure you still get results returned when there are no entries in Post_Photos which match the PostID i.e.
LEFT JOIN Post_Photos ON Posts.ID = Post_Photos.PostID)
If Post_Photos.Photo is a string (representing the name of the photo, or a filename), you can resolve your second issue by changing Post_Photos.Photo in your select to GROUP_CONCAT(Post_Photos.Photo) i.e.
SELECT Posts.*, Profiles.ProfilePhoto, Users.Name, Users.Username, GROUP_CONCAT(Post_Photos.Photo) AS Photo
Then in your PHP you can do this:
$photos = explode(',', $row['Photo']);

One record 27 times

I have a big problem with MySQL. I want to write script like facebook newsfeed.
My query return me 27 the same records. I don't know why.
How it works?
Script displaying posts written by me, my friends or my profile.
My tables:
users:
id, firstname, lastname
friends:
friend1, friend2, status, date
wall:
update_id, author, to_profile, content, date, photos
My query:
SELECT wall.update_id, wall.author, wall.to_profile, wall.content, wall.date, wall.photos, users.*, friends.sender_id, friends.friend_id, friends.status
FROM
wall
INNER JOIN friends ON
wall.author = friends.sender1
AND friends.friend2 = '".$_SESSION['id']."'
AND friends.status = '1' OR wall.author = '".$_SESSION['id']."'
OR wall.to_profile = '".$_SESSION['id']."'
INNER JOIN users ON users.id = wall.author
ORDER BY wall.date DESC
I also want to display post written by pages which I liked.
I created tables:
pages:
page_id, page_name
page_likes:
page_id, user_id, date
and *pages_wall:**
like_id, page_id, user_id, date
How to connect this to my query? And (the most important) how to repair my query?
Thanks in advance,
Matthew
That's a lot of joining going on. Try using your JOINs just to connect the tables, and then use WHERE to cut down the results. Because as it stands, those ORs aren't working like you probably think they are, they need some () around them.
I think you need some structural changes to this database for it to work well in the future. I'd add an ID field to friends, even if just on the admin side, you're going to want to manage those records.
Also, you shouldn't be querying user.* in this query. It seems like you want to pull out every user setting... for every single wall post. This will get rid of "INNER JOIN users ON users.id = wall.author " at the end which will help. Get that information in it's on query prior to calling this wall display.
SELECT *
FROM users
WHERE users.id = wall.author

Retrieving like counts on entries from SQL

I've been adding a like feature to an entries database... here's the structure of the DBs:
**Users**
user_id
user_name
etc.
**Entries**
entry_id
entry_content
etc.
**Likes**
user_id
entry_id
(It's a little more complicated than that, there are groups/categories, but that should explain it fine...) Here's the SQL query I'm working with at the moment:
SELECT
entries.*,
DATE_FORMAT(entry_date, "%M %D, %Y") as entry_date,
groups.group_short_name,
users.user_name, users.user_id,
FROM entries
INNER JOIN groups ON groups.group_id = entries.group_id
INNER JOIN users ON users.user_id = entries.user_id
ORDER BY entry_date DESC
I'm trying to also retrieve likes per entry with this query and wondering if it is possible. I've been trying:
COUNT(DISTINCT likes.like_id) as likes
with
LEFT JOIN likes ON likes.entry_id = entries.entry_id
But I don't think that is anywhere near right. Am I way off? Is this possible? Hope it all made sense.
Thanks for the help in advance.
Give your tables aliases, for one..
FROM entries e
Then add a column query:
select e.*, (select count(*) from Likes where entry_id = e.entry_id) as entry_likes
Add:
GROUP BY entries.entry_id
See if that works.

Need help with a multiple table query in mysql

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.

Categories