Check if row has specific childs on join - php

I want to make a SQL to get the user which name is Mark and are the author of the posts with ids 1 and 3.
NOTE: It is unknown how many posts I need to check for. So it might need to generate that part of the SQL query using PHP.
How can that be done?
Users Table:
+----+----------+
| id | name |
+----+----------+
| 1 | Mark |
| 2 | John Doe |
+----+----------+
Posts Table
+----+-------------+-------------+
| id | text | author_id |
+----+-------------+-------------+
| 1 | First Post | 1 |
| 2 | Second Post | 2 |
| 3 | Last Post | 1 |
+----+-------------+-------------+
This is just a sample case of use, not real data.
NOTE: I know how to check if user is author on one post, but not multiple in the same row. So basicly that is what I need help with, I guess it must be a left join.
For making the check for the user named Mark and check if he is author for post id 1 I do the following:
SELECT users.*
FROM users
INNER JOIN posts
ON users.id = posts.author_id
WHERE
users.name = 'Mark'
&&
posts.author_id` = 1

I just selected the id from users. If you need more columns then just add it to the select and the group by clause.
SELECT users.id
FROM users
INNER JOIN posts ON users.id = posts.author_id
WHERE users.name = 'Mark'
AND posts.author_id in (1,3)
GROUP BY users.id
HAVING count(distinct posts.author_id) = 2

Use a sub-query to find only users with both 1 and 3:
SELECT users.*
FROM users
WHERE users.name = 'Mark'
and 2 = (select count(distinct posts.id)
where users.id = posts.author_id
and posts.id IN (1,3))

SELECT users.name, posts.posts, posts.authorid
FROM users INNER JOIN posts ON users.id = posts.authorid where posts.authorid = 1

You need to use HAVING clause to achieve desired outcome:
SELECT users.name
FROM users
INNER JOIN posts
on users.id = posts.author_id
WHERE users.name = 'Mark'
GROUP BY users.name
HAVING COUNT(posts.author_id) > 1

Related

get ALL posts AND post the user liked MySQL

I'm triying to get ALL posts and a variable "liked" next to the post to check if the user liked it or not.
I have three table with theses :
-posts
+----+---------+---------+
| id | user_id | text |
+----+---------+---------+
-votes
+----+-----------+---------+---------+
| id | type_vote | user_id | post_id |
+----+-----------+---------+---------+
-users
+---------+---------+
| id_user | etc.. |
+---------+---------+
I check the others answers but it don't solve my problem. Also I tried this code :
SELECT id, text,
IF('$uid' IN (SELECT id FROM votes WHERE user_id='$uid'), 1, 0) AS liked
FROM posts
INNER JOIN users
ON users.id_user = posts.user_id
WHERE posts.user_id = '$uid' OR posts.user_id
ORDER BY posts.created_at desc
But it returns only posts created by user and the liked variable doesn't work..
What am I missing?
Thanks in advance !
EDIT :
I managed to get the id of the votes next to the appropriate post, how to transform it in 0 if NULL and 1 if id exists ?
SELECT p.*,(SELECT id from votes where user_id = '$uid' AND post_id = p.id) as liked from posts p
I get a result like :
+----+------+---------+---------------+
| id | text | user_id |liked |
+----+------+---------+-----+---------+
| 1 | blab | 5476zef |NULL OR post_id|
+----+------+---------+---------------+
I am not sure about the relationship between "likes" and "votes". However, if you want all posts and additional information, then a left join or correlated subquery comes to mind.
I think this may be what you want:
select p.*
(exists (select 1
from votes v
where v.post_id = p.id and v.user_id = $uid
)
) as user_flag
from p;
There may also be some condition on type_vote, but your question doesn't explain how that field is used.
SELECT products.title,isfav.isFavourite
FROM
products
LEFT JOIN isfav
ON products.product_id = isfav.product_id
and isfav.user_id=2
ORDER BY
products.added_date
You can also use an if-condition:
IF(liked IS NULL,0,1)
You can either add a column or replace liked with your expression.

MySQL inner join AND turn rows into colums

I'm having difficulty figuring out how to create the proper syntax for my query.
Here is what i'm pulling. I have 2 tables.
Table 1 : Fields (user_id, name)
Table 2 : Fields (user_id, type, are_code, phone_number).
Table 1 can only have 1 record per user_id.
1 | John Doe
Table 2 can have up to 3 records per user_id:
1 | Home | 123 | 456.4567
1 | Work | 000 | 987.1467
1 | Mobi | 098 | 987.1756
How can i select everything so that my table will result in 1 record pulled like so :
user_id | name | home# | work# | mobi#
I tried this, which duplicates and doubles rows based on amount of entries within Table 2.
SELECT a.user_id,
b.area_code, b.phone_number
FROM users a
INNER JOIN user_contact_phones b ON a.user_id = b.user_id
That unfortunately returned 3 rows which is not good :(.
1 | John Doe | area | home# |
1 | John Doe | area | work# |
1 | John Doe | area | mobi# |
Any help and or pointers would be greatly appreciated.
Try this out:
SELECT
u.user_id,
u.name,
MAX(CASE WHEN p.type = 'Home' THEN phone_number END) HomeNumber,
MAX(CASE WHEN p.type = 'Work' THEN phone_number END) WorkNumber,
MAX(CASE WHEN p.type = 'Mobi' THEN phone_number END) MobiNumber
FROM phones p
JOIN users u ON p.user_id = u.user_id
GROUP BY u.user_id, u.name
Output:
| USER_ID | NAME | HOMENUMBER | WORKNUMBER | MOBINUMBER |
|---------|----------|------------|------------|------------|
| 1 | John Doe | 456.4567 | 987.1467 | 987.1756 |
Fiddle here.
Also note that you can remove u.name if u.user_id determines u.name... which is most likely the case as it seems to be a primary key. That would speed things up a little bit.
Note: This assumes that you cant have more than one same type for the same user (as it is in your example data, which only has one column for home, work and mobile.
Use user_contact_phones.type to get exact what you want, like-
SELECT a.user_id,
b.area_code, b.phone_number
FROM users a
INNER JOIN user_contact_phones b ON a.user_id = b.user_id where b.type='Home'
Here's a solution that will work:
select u.user_id, u.name,
thome.area_code as home_area_code, thome.phone_number as home_phone_number,
twork.area_code as work_area_code, twork.phone_number as work_phone_number,
tmobi.area_code as mobi_area_code, tmobi.phone_number as mobi_phone_number
from table1 u
left outer join table2 thome on u.user_id = thome.user_id and thome.type = 'Home'
left outer join table2 twork on u.user_id = twork.user_id and twork.type = 'Work'
left outer join table2 tmobi on u.user_id = tmobi.user_id and tmobi.type = 'Mobi'
Please note the use of left outer join instead of inner join in case the record for a particular type does not exist. You will get null values for those columns in your result set with left outer join. With inner join, you would not get a result for a user that did not have all three types. Good luck!

Show "0" in COUNT column when WHERE does not match?

What I would like to do is retrieve all data from a table, and order them by the number of games the user played in a specific category. Is there any way I can use some sort of "COUNT WHERE" sql statement?
here's what i have so far. it will only return the user if they have played a game in the "fps" category, but I want it to show all users in descending order even if they have not played an fps game. please excuse my crappy tables
SELECT user_data.user, COUNT(played_games.game_cat) as 'count'
FROM user_data, played_games
WHERE user_data.user_id = played_games.user_id and played_games.game_cat = 'fps'
GROUP BY user_data.user_id
ORDER BY 'count' DESC;
user_data table
user_id | user
1 | jeff
2 | herb
3 | dug
played_games table
id | user_id | game | game_cat
1 | 2 | kill | fps
2 | 1 | shoot| fps
3 | 2 | COD | fps
4 | 3 | dogs | cas
You need a LEFT OUTER JOIN to get the records even if a corresponding record does not exist in the other table.
SELECT user, coalesce(count(game_cat), 0) as count
FROM user_data LEFT OUTER JOIN played_games
ON user_data.user_id = played_games.user_id AND played_games.game_cat='fps'
GROUP BY user_data.user_id
ORDER BY count desc;
Gives the following result on my screen
+------+-------+
| user | count |
+------+-------+
| herb | 2 |
| jeff | 1 |
| dug | 0 |
+------+-------+
This is how I'd do it. No subquery, no COALESCE, no COUNTIF junk.
SELECT `users`.`user`, COUNT(`played_games`.id) AS `c`
FROM `users`
LEFT OUTER JOIN `played_games` ON
`users`.`user_id` = `played_games`.`user_id`
AND `played_games`.`game_cat` = "fps"
GROUP BY `users`.`user_id`
ORDER BY `c` DESC, `user` ASC
SQLFiddle (not sure if you can link them like this...)
Try this:
SELECT ud.user, coalesce(sum(pg.game_cat = 'fps'), 0) Total
FROM user_data ud
LEFT JOIN played_games pg ON ud.user_id = pg.user_id
GROUP BY ud.user_id
ORDER BY Total DESC
This will show all users and the amount of times they've played a game with category 'fps'.
The coalesce one is promising, but doesn't work for me, sigh~ I just found NULLIF is a good way to solve this problem. Remember to use LEFT JOIN
COUNT( NULLIF(TABLE.ATTR, 1) ) AS total_count
The TABLE.ATTR is some field that can be NULL, here is an example:
SELECT Posts.*, COUNT( NULLIF(Comments.user_email, 1) ) as comment_num
FROM (`Posts`)
LEFT OUTER JOIN `Comments` ON `Comments`.`post_id` = `Posts`.`id`
GROUP BY `Posts`.`id`
LIMIT 5
Got the idea from http://www.bennadel.com/blog/579-SQL-COUNT-NULLIF-Is-Totally-Awesome.htm
Below query the all game category with user id and order by count
select * from (SELECT user_data.user, COUNT(played_games.game_cat) as 'count'
FROM user_data, played_games
WHERE user_data.user_id = played_games.user_id(+) GROUP BY user_data.user_id)
order by count desc

Joining Query with Multiple Tables Based on Values

Supposed I have a table posts like below:
| id | type | ref_id |
-----------+--------------+ ---------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 3 | 3 |
| 4 | 1 | 4 |
| 5 | 2 | 5 |
| 6 | 3 | 6 |
The type field is to join with other tables, so for example 1=blogs, 2=reviews, 3=photos, and each of them have respective fields, while ref_id is the ID of the blog/review/photo.
What i want to do is to show all latest posts (order by id DESC), while joining with all other tables based on the value of the type, but I want to do it with one query if possible. My no-good query is below:
SELECT * FROM posts
LEFT JOIN blogs ON posts.ref_id = blogs.ID AND posts.type = 1
LEFT JOIN reviews ON posts.ref_id = reviews.ID AND posts.type = 2
LEFT JOIN photos ON posts.ref_id = photos.ID AND posts.type = 3
ORDER BY posts.id DESC
The query doesn't result in anything. Another alternative is to loop the SELECT * FROM posts query and do another query based on the type, but if possible, I'd like to do it in 1 go.
Thanks for the help.
To see why your query does not return anything, consider moving the " AND posts.type = " from JOIN to WHERE clause. It will be:
select * from posts ... where type=1 and type=2 and type=3
Obviously, it will return no results. I know it is not the answer to your question, but I would consider a small change in your table definitions:
(table name: fields)
posts: id
blogs: id, post_id
reviews: id, post_id
photos: id, post_id
In this case you will be able to construct simpler and more traditional queries:
select * from posts
left join blogs on blogs.post_id = posts.id
left join reviews on reviews.post_id = posts.id
left join photos on photos.post_id = posts.id
I guess you want something like this:
( SELECT posts.*, blogs.*
FROM posts
JOIN blogs
ON posts.ref_id = blogs.ID
AND posts.type = 1
UNION ALL
SELECT posts.*, reviews.*
FROM posts
JOIN reviews
ON posts.ref_id = reviews.ID
AND posts.type = 2
UNION ALL
SELECT posts.*, photos.*
FROM posts
JOIN photos
ON posts.ref_id = photos.ID
AND posts.type = 3
)
ORDER BY posts.id DESC

SELECT multiple table

i need some help here,
table "friends"
+------+-------------+-----------+
id | friend_id | user_id |
+------+-------------+-----------+
1 | 1222 | 99999 |
+------+-------------+-----------+
2 | 48989 | 1492 |
+------+-------------+-----------+
table "users"
+------+-------------+---------------+
id | user_name | user_image |
+------+-------------+---------------+
99999 | Mark | img/abc.jpg |
+------+-------------+---------------+
1222 | Tom | img/xyz.jpg |
+------+-------------+---------------+
etc. | etc. | etc.. |
+------+-------------+---------------+
i want SELECT table friends and make WHERE statement :
etc : ... WHERE user_id=$_SESSION[user_id] ...
and will display data from table users
ok , let say :
my current id is 99999 so in table friends is match only 1222 , so this will display all data(image,etc..) from id 1222(Tom) from table users.
So my question here is how i need to write this code for generate users data ?
*i try to use UNION and LEFT JOIN..but no luck..still newbie..
$user_id = intval($_SESSION['user_id']);
$friends_of_user = mysql_query('
SELECT
f.*, u.*
FROM
friends f
LEFT JOIN
users u
ON
u.id = f.friend_id
WHERE
f.user_id = '.$user_id);
and to exclude all users which doesn't have profiles in users table, just change LEFT JOIN to JOIN
I'd use the following code:
$user_id = mysql_real_escape_string($_SESSION['user_id']);
$sql = "SELECT f.*
FROM users u
INNER JOIN friends f ON (u.user_id = f.friend_id)
WHERE u.user_id = '$user_id' ";

Categories