MySQL count in "complex" SQL query - php

I have the following SQL query: Let me describe it to you quickly. I wanna develop a soccer tip game. I have 4 tables: apps, tips, users, games.
Relations:
apps 1 to N users
user 1 to N tips
game 1 to 1 tip
Instead of listing all games where the User had a successful tip, I just want to list the u.userId with the COUNT of successful tips. Check out my SQL:
SELECT
t.*, u.*, g.*
FROM
tips AS t,
users AS u,
games AS g
WHERE
u.userAppId = 4 AND
t.tipUserId = u.userId AND
g.gameResult = t.tipGameResult
I guess I somehow have to implement a COUNT and u.userId instead of
t.*, u.*, g.*
but I am not 100% sure how to do it. Do you have any suggestions?

SELECT
u.userid, count(*)
FROM
tips AS t,
users AS u,
games AS g
WHERE
u.userAppId = 4 AND
t.tipUserId = u.userId AND
g.gameResult = t.tipGameResult
group by u.userid
As mentioned in comment below, the group by on user id will give you
userid|count(*)

Related

PHP mySQL retrieve unique correct data from multiple tables

So i am making this webpage (for fun to practice web dev) where users can rate or comment on a movie. One page I have is where you click on the movie for full details and it lists all the ratings and comments (together if the user has commented by review and rated through a page called "reviewMovie"...which if they went this way the rating is mandatory, otherwise they can comment on this page "listMovieReviews").
The problem I am having is incorrect details when doing my queries
the discussion table stores: the discussion ID (primary key) the timestamp of the
comment, the comment, the user who made the comment, and the movie they commented
about.
the discussion table stores: the discussion ID (primary key) the timestamp of the
comment, the comment, the user who made the comment, and the movie they commented
about.
the rating table stores: the rating ID (primary key), the movie being rated, the
user who did the rating, and the rating score (out of 10)
So some examples of the combined data are:
User1 (user1) has rated "American Psycho" a 4/10 and has made a comment "comment1" on
it
User2 (admin..for testing purposes) has rated "American Psycho" a 8/10 and has made a
comment "comment2" on it
So on the page that lists the details of "American Psycho" and the ratings/comments I should have this list of ratings and comments:
<TIMESTAMP FOR COMMENT1> User1 Rating 4/10 "comment1"
<TIMESTAMP FOR COMMENT2> admin Rating 8/10 "comment2"
Using the following queries:
SELECT *
FROM discussion
INNER JOIN users ON discussion.userID = users.userID
WHERE discussion.movieID = <American Psycho's Movie ID>;
AND
SELECT *
FROM ratings
INNER JOIN movies ON ratings.movieID = movies.movieID
WHERE ratings.movieID = <American Psycho's Movie ID>;
I get this:
<TIMESTAMP FOR COMMENT2> admin Rating 4/10 "comment2"
<TIMESTAMP FOR COMMENT2> admin Rating 8/10 "comment2"
I have tried several other INNER JOINS with joining the table that stores user information and table that stores movies information but I keep getting mixed data
Also tried DISTINCT and UNION but still to no avail
Where am I going wrong??
Also first post so sorry If I have not been too clear, bad formatting, or not shown enough work but I am really really stuck
I assume:
A movie could have from 0 to n comments.
A movie could have from 0 to n ratings.
A user could rate a movie only once or none.
A user could comment a movie from 0 to n times.
Your queries are fine, maybe your problem is in your php code.
You have to account that a user maybe comment a movie several time and never rated it.
In second query you should JOIN with user (instead of with movie, because you do not get movie information) to get the user name.
Maybe you should display the info in two table: one for ratings and other for comments.
(You have to replace quotation marks by movie ID)
SELECT u.userName, r.score
FROM ratings AS r
INNER JOIN users AS u ON r.userID = u.userID
WHERE r.movieID = ?;
SELECT u.userName, d.commentTime, d.comment
FROM discussion AS d
INNER JOIN users AS u ON d.userID = u.userID
WHERE d.movieID = ?;
You could group all comments per user in one row this way (but I think this is not what you are looking for):
SELECT u.userName, GROUP_CONCAT(CONCAT(d.commentTime, ': ', d.comment) SEPARATOR '; ') AS comments
FROM discussion AS d
INNER JOIN users AS u ON d.userID = u.userID
WHERE d.movieID = ?
GROUP BY u.userName
I think do not have sense to make one query in this case, but if you want get all data in one query you could try something like this:
You will have a comment per row, so for example if a user make two comment you will have two rows for the same user with the same score.
First I get all user that comment or rating the selected movie and make a CROSS JOIN between movie and these users. Then I make a LEFT JOIN with discussion ON movieID and userID and another LEFT JOIN with ratings ON movieID and userID.
You need to make LEFT JOIN instead of INNER JOIN because if a movie do not have ratings or comments your result will be empty.
In SELECT clause you should list only the columns that you need.
SELECT *
FROM movies m
CROSS JOIN (SELECT d.userID
FROM discussion d
WHERE d.movieID = ?
UNION
SELECT r.userID
FROM ratings r
WHERE r.movieID = ?) AS u
LEFT JOIN discussion AS d ON m.movieID = d.movieID AND u.userID = d.userID
LEFT JOIN ratings AS r ON m.movieID = r.movieID AND u.userID = r.userID
LEFT JOIN users ON u.userID = users.userID
WHERE m.movieID = ?;
You need to join all three tables.
SELECT *
FROM movies AS m
JOIN ratings AS r ON r.movieID = m.movieID
JOIN discussion AS d ON d.userID = r.userID AND d.movieID = m.movieID
WHERE m.movieID = <American Psycho's Movie ID>
ORDER BY r.userID, d.timestamp
This will repeat the movie and rating information for each comment. You can remove those duplicates in the application code that displays the results. See How can i list has same id data with while loop in PHP? for an example of how to do this.
SELECT * FROM movies AS MOVIE
JOIN ratings AS RATING ON `RATING.movieID` = `MOVIE.movieID`
JOIN discussion AS DISCUS ON `DISCUS.userID` = `RATING.userID`
WHERE `MOVIE.movieID` = <SOME Movie ID>
ORDER BY `RATING.userID`, `DISCUS.timestamp`

SQL: Selecting count of multiple tables

I don't think this will be too complicated to explain, but certainly complicated to get it working.
First of all, I have a couple of tables regarding users comments, one table for each section (forum, articles etc), as shown below:
site_users (id, username, ...) [Table that holds user's info]
site_articles_comments (id, user_id, comment, ...) [Where user_id = site_users.id]
site_forum_comments (id, user_id, comment, ...) [Same for site_articles_comments]
The thing is that every new row is a new comment and users can comment multiple times, which means that more rows are being added, thus making the need of sorting the number of rows to get the amount of comments in some sort of ranking system.
I was able to make a simple forum rank by doing this simple query:
SELECT u.id, u.username, COUNT(r.id) AS rank FROM site_users AS u LEFT
JOIN site_forum_comments AS r ON u.id = r.user_id GROUP BY u.username,
u.id ORDER BY rank DESC LIMIT :l
This query sorts all users from the database, where the user who has commented the most is always on top.
What I need, in the other hand, is to have a global ranking system, which sums the amount of comments in each section (articles, forum etc) and displays the users accordingly.
I was playing around with the sql to do that and the last thing I came up with was this huge query:
SELECT u.id, u.username, (COUNT(a.id) + COUNT(f.id)) AS rank FROM
site_users u LEFT JOIN site_articles_comments a ON a.user_id = u.id
LEFT JOIN site_forum_comments f ON f.user_id = u.id GROUP BY
u.username, u.id ORDER BY rank DESC LIMIT :l
This, however, returns null. What could I possibly do to achieve the result I want?
Thanks in advance,
Mateus
EDIT1: Sorry for the lack of information, this is regarding MySQL.
The problem is math with nulls, and ordering with nulls (check into the "NULLS LAST" option for overriding the default ordering which returns the nulls first for a descending order).
In your case, with the outer joins, if the user has a ton of article comments but no forum comments, well, 100 + null = null in Oracle math. So to get the math to work you need to make null=0. That's where NVL() comes in (and also has the nice side-effect of eliminating pesky nulls from your result set)!
SELECT u.id, u.username, (NVL(COUNT(a.id),0) + NVL(COUNT(f.id),0)) AS rank
FROM site_users u
LEFT JOIN site_articles_comments a ON a.user_id = u.id
LEFT JOIN site_forum_comments f ON f.user_id = u.id
GROUP BY u.username, u.id ORDER BY rank DESC LIMIT :l
I see you have both MySQL and Oracle in your tags - the above is for Oracle. If for MYSQL use COALESCE(COUNT(),0) instead.
try SELECT u.id, MIN(u.username) AS username, (COALESCE(COUNT(DISTINCT(a.id)),0) + COALESCE(COUNT(DISTINCT(f.id)),0)) AS rank
FROM site_users AS u
LEFT JOIN site_articles_comments AS a ON (a.user_id = u.id)
LEFT JOIN site_forum_comments AS f ON (f.user_id = u.id)
GROUP BY u.id
ORDER BY rank DESC
LIMIT :l

Advice on MySQL JOIN

I am struggling to get me head round the MySQL Join function.
Here is two tables I have:
User table:
admin_id username
*1 peter93
2 stackoverflowrocks
3 user3*
Admin details table:
admin_username description image
pedro93 [text] [image_url]
stackoverflowrocks [text] [image_url]
user3 [text] [image_url]
I know usualy to link two databases together you would use ID numbers, but in this case I want to join the two tables where admin_username = username.
Can anyone help me please? It is for a PHP script if that helps.
Thanks in advance!
Peter
So that's fine. You can join on anything you like.
select *
from user
inner join admin
on user.username=admin.admin_username
joining by a string column is the same as joining by Id
select * from admin_table
inner join admin_details on admin_table.username = admin_details.admin_username
But make sure you have and index for the username columns, or else your queries will go slow when you have lots of records
You can join on pretty much any field but you may wish to keep in mind datatype mismatching, indexing etc
All users
SELECT u.*, a.*
FROM users AS u
LEFT JOIN admin AS a
ON u.username = a.username
All users that are admin
SELECT u.*, a.*
FROM users AS u
INNER JOIN admin AS a
ON u.username = a.username
All admin
SELECT u.*, a.*
FROM users AS u
RIGHT JOIN admin AS a
ON u.username = a.username

Complex Mysql query to combine 3 tables Data?

I have a table in which I store followers, I have another table in which I store friendships
Now I have third table which stores stream data.
Its a social network, there are many reasons so I don't wish to have one table for follower & friendships (Means facebook subscriptions/friends)
Can someone presents a way how should I query streams table to pick activities of both friends & followings ?
Any help would be really appreciated, thank you
Here is simple Database Scheme, its not really like this but almost!
Okay here is database tables schema please,
Followers table.
Row_ID
User_ID
Following_User_ID
Friends Table
Row_ID
User_ID
Friend_ID
Stream Table
Row_ID
User_ID
Contents_ID
Time
Type
What are you looking for is probably best done as two distinct results sets... or a union of the two.
Select "friend" as src, author, post from friends f inner join streams s on s.author = f.id
union
Select "follower" as src, author, post from followers f inner join streams s on s.author = f.id
This is just some pseudo coding but it should give you an idea of how to proceed. Without knowing your database schema, this is the best I can offer.
Edit:
This might be what your looking for then
select user_id, contents_id, time from (
select user_id, contents_id, time
from followers f inner join stream s on s.user_id = f.user_id and f.user_id = "username"
union
select user_id, contents_id, time
from friends f inner join stream s on s.user_id = f.user_id and f.user_id = "username"
) order by time desc
This will return the data in time order, descending.

php mysql join multiple table

I have two table
User
userID username email
1 abc abc#abc.com
2 def def#def.com
3 ghi ghi#ghi.com
Referral
refID userID invEmail
1 1 abc#def.com
2 1 omg#mog.com
3 1 def#def.com
So what i plan is to give a invited user 5 point meanwhile a inviter 10 point, so basically userID 1 gained 30 meanwhile userID 2 gained 5. The point i can do in PHP but one part i faced difficulty is when a invEmail to be identified. I don't mind separating into multiple queries if its will work.
How do i show this in sql?
I tried something like
SELECT *, count(r.userID) FROM user u, referral r WHERE u.userID = r.userID OR u.email = r.invEmail GROUP BY r.userID
It returned wrong value.
What i would like it to return, how much count is there inviter and invitee(matched email who has registered based on inviter invitation)
How should i do it?
Thank you.
Edit: i forgot to add something into question, what if i wanted the inviter to receive 10 points only if invitee registered? what i meant is that, only if invEmail exists in u.email then only userID received 10 point. Sorry for my mistake.
You might be able to do something like this:
select points.userId, points.username, points.email, sum(points.points)
FROM
(select u.*, count(*)*10 as points
from user u
join referral on u.userID = r.userID
join user verify_user on r.invEmail = verify_user.email
group by u.userID, u.username, u.email
UNION
select u.*, count(*)*5 as points
from user u
join referral on u.email = r.invEmail and u.userID != r.userID
group by u.userID, u.username, u.email
) as points
group by points.userId, points.username, points.email
I think you need two separate selects to get the points for each type of registration, combined with a union statement.

Categories