I have a website that displays poll after poll to a register user, and stores his vote in a table.
A simple structure of the database would be as follows (there are much more fields, but they don't contribute much to the question, so I removed them):
Polls(pollId)
Votes(pollId, userId, vote)
Now I want to run a MySql query to select all polls within the 'Polls' table, except for the polls that the current user had already voted on (which could be determined from the 'Votes' table)
Is it possible to make that using a MySql select statement alone, or will I have to select all polls first, and use some Php logic to filter out the ones already voted on by the user?
Thanks in advance!
SELECT *
FROM Pools
WHERE id NOT IN (
SELECT poolId
FROM Votes
WHERE userId = 142
)
Try something like this:
select p.pollid from polls p where p.pollid not in (select v.pollid from votes v where userId = {USERID})
Related
I've got a system on my website which is very similar to Facebook, where you can post statuses and your people can comment on your status, like it etc. This all gets inserted in the database in the following format, with child tables of the likes and comments with foreign keys set up in case the parent status gets deleted, the likes and comments get deleted with it.
I also have a friends table which contains the user ID of the user that started the friend request, the user ID of the user that has to either accept it or deny it, and the status of the record, whether it's accepted, denied or pending.
There's also a "users" table which contains the normal malarkey, such as emails, passwords etc. All records have a unique ID however, in the column "userID".
The query I have at the moment loads all statuses regardless of whether the status owner is your friend or not. The current query looks like this (I'm working in ColdFusion so ## are the variables passed to the function)
SELECT *,
(SELECT COUNT(*) FROM status_likes WHERE likeStatusID=statusID) AS StatusLikeCount,
(SELECT COUNT(*) FROM status_comments WHERE SID=statusID) AS StatusCommentCount
FROM status, users
WHERE statusOwner=userID
AND statusType='user'
ORDER BY statusDateTime DESC
LIMIT #args.indexStart#,#args.indexEnd#;
I need this query to only load statuses if the owner of the status is your friend. I can call a query to load a users friends and append a string containing the user ID's of all the friends, such as: "652,235,485,975" etc.
I tried doing an IN in the query so there was an extra line:
AND (statusOwner=#val(args.userID)# OR statusOwner IN (#usersFriendsString#))
However this brought back duplicate results and when I tried GROUP BY on the status owner, it didn't bring back records that it should have.
Any MySQL gurus out there able to help?
You should use something like that :
SELECT
s.*,
(SELECT COUNT(*) FROM status_likes WHERE likeStatusID=s.statusID) AS StatusLikeCount,
(SELECT COUNT(*) FROM status_comments WHERE SID=s.statusID) AS StatusCommentCount
FROM Users u
JOIN Friend f ON f.friendOwner = u.id
JOIN Status s ON s.statusOwner = f.id
WHERE u.id = <...>
ORDER BY s.statusDateTime DESC
You can use WHERE clause if you can't use a JOIN instruction.
Or you can use a IN instruction populated by a SELECT that retrieve all requiered status ids.
I have a table with 6 columns- Date, time, action, user_id, channel, and time_and_date.
Action refers to open or close, when a user starts or end watching a tv channel.
My tasks are as following
to get an overview of the data:
- find the one-time users (who used the service only once or in only one day and
never came back) for each channel, each genre, each community
Anoother table provides the user_id, genre(news, sport....)
How can I find the one time users for those requirements?
You can try something like
SELECT FROM first_table LEFT JOIN users ON first_table.user_id=users.id GROUP BY users.id HAVING COUNT(users.id)=1
You can join your genre table after for selecting over genre channels...
To get the one-time users:
select user_id ,min(channel) as channel, min(genre) as genre, min(community) as community
from action_table
group by user_id
having min(date) = max(date);
Note the having clause. This guarantees that a users has only one date (but not necessarily one record).
This returns one value for each of the three dimensions -- for a one-time user they are the same. For someone who visits multiple times in one day, it chooses one value.
Sounds something like this:
select user_id, count(*)
from action_table
where action = 'open'
group by user_id
having count(*) = 1
order by user_id
Please forgive my ignorance here. SQL is decidedly one of the biggest "gaps" in my education that I'm working on correcting, come October. Here's the scenario:
I have two tables in a DB that I need to access certain data from. One is users, and the other is conversation_log. The basic structure is outlined below:
users:
id (INT)
name (TXT)
conversation_log
userid (INT) // same value as id in users - actually the only field in this table I want to check
input (TXT)
response (TXT)
(note that I'm only listing the structure for the fields that are {or could be} relevant to the current challenge)
What I want to do is return a list of names from the users table that have at least one record in the conversation_log table. Currently, I'm doing this with two separate SQL statements, with the one that checks for records in conversation_log being called hundreds, if not thousands of times, once for each userid, just to see if records exist for that id.
Currently, the two SQL statements are as follows:
select id from users where 1; (gets the list of userid values for the next query)
select id from conversation_log where userid = $userId limit 1; (checks for existing records)
Right now I have 4,000+ users listed in the users table. I'm sure that you can imagine just how long this method takes. I know there's an easier, more efficient way to do this, but being self-taught, this is something that I have yet to learn. Any help would be greatly appreciated.
You have to do what is called a 'Join'. This, um, joins the rows of two tables together based on values they have in common.
See if this makes sense to you:
SELECT DISTINCT users.name
FROM users JOIN conversation_log ON users.id = converation_log.userid
Now JOIN by itself is an "inner join", which means that it will only return rows that both tables have in common. In other words, if a specific conversation_log.userid doesn't exist, it won't return any part of the row, user or conversation log, for that userid.
Also, +1 for having a clearly worded question : )
EDIT: I added a "DISTINCT", which means to filter out all of the duplicates. If a user appeared in more than one conversation_log row, and you didn't have DISTINCT, you would get the user's name more than once. This is because JOIN does a cartesian product, or does every possible combination of rows from each table that match your JOIN ON criteria.
Something like this:
SELECT *
FROM users
WHERE EXISTS (
SELECT *
FROM conversation_log
WHERE users.id = conversation_log.userid
)
In plain English: select every row from users, such that there is at least one row from conversation_log with the matching userid.
What you need to read is JOIN syntax.
SELECT count(*), users.name
FROM users left join conversion_log on users.id = conversation_log.userid
Group by users.name
You could add at the end if you wanted
HAVING count(*) > 0
This might not be possible but would be amazingly awesome if it were. I have the following basic table structure:
groups
group_id
other_stuff
users
user_id
other_stuff
users_to_groups
user_id
group_id
other_stuff
events
event_id
group_id (where the event belongs)
other_stuff
events is actually a set of tables for the various actions a user can perform on the site.
I would like to be able to perform a query on of the tables and have it return a result something like:
event_type event_id info_columns ...
user_join user_to_group_id
photo_upload photo_id
comment comment_id
where the value in the event_type column would be one generated by the query based on the table name of the source content.
I know I can do this using multiple queries and then piecing them together in PHP, but I was thinking that maybe there is a way to do it entirely in MySQL. Is something like this even possible? If so, what are the basic steps to make it happen?
if you have a number of select statements, and you get the data you want in each, then of course you can join them.
Others have asked similar questions, mysql-join-most-recent-matching-record-from-one-table-to-another
Now, given you're only asking for the latest event. your pseudo code goes
select <userinfo>
from users
join groups
on user=group
join (select lastest event by group
from events
) as tmp
on group=tmp
That way you do 1 query, you hand off that work to the database
There are two tables. One is users info "users", one is comments info "comments".
I need to create new field "comments" in users table, that contains number of comments of that user. Table "comments" has "user" field with user's id of that comment.
What is optimal way to count number of comments by every user so far?
With php you should write script that selects every user and than count number of his comments and then update "comments" field. It is not hard for me, but boring.
Is it possible to do it without php, only in MySQL?
UPDATE TABLE users SET CommentCount = (SELECT COUNT(*) FROM comments WHERE AuthorUserId = users.id)
Why do you want to store it there anyway?
Why not just show it combined query?
select users.name, count(comments.id) as comment_count
from users
join comments on users.id=comments.user_id
group by users.id
If you want to do it your way then include
update users set comment=comment+1 where id=$user_id
into the script where you store the comment.
And
update users set comment=comment-1 where id=$user_id
into the place where user can delete his comment. Otherwise your data might be out of sync when user adds new commnts and you haven't run the script yet.
Yes, it is possible.
This is called table joining.
You don't add another field to the users table, but to the resulting table.
SELECT users.*, count(comments.id) as num_comments
FROM users,comments
WHERE comments.cid=users.id
GROUP BY users.id
Such a query is what relational databases were invented for. Do not revert it to the plain text file state. There is many reasons to make it that way.
http://en.wikipedia.org/wiki/Database_normalization <-- good text to read