I have two table for a multiple choice questionnaire (each user answers a series of questions):
users (userID, name, email)
votes (voteID, userID, questionID, answerID)
Sample data (users):
0, Some Name, some#thing.com
1, Other Name, some#one.com
Sample data (votes):
0, 1, 1, 1
1, 1, 2, 2
2, 1, 3, 2
I would like select all users who has the correct answers.
I tried this (where I've hardcoded the answers in):
$sql = "SELECT users.userID, users.name, users.email FROM users
INNER JOIN votes ON (users.userID = votes.userID)
WHERE (votes.questionID = '1' AND votes.answerID = '1')
AND (votes.questionID = '2' AND votes.answerID = '2')
AND (votes.questionID = '3' AND votes.answerID = '2')
AND (votes.questionID = '4' AND votes.answerID = '3')
AND (votes.questionID = '5' AND votes.answerID = '1')
GROUP BY users.userID";
But this doesn't return anything.
I've also tried something like this (where I've also hardcoded the answers in):
$sql = "SELECT users.userID, users.name, users.email FROM users
INNER JOIN transfertipsvotes ON (users.userID = transfertipsvotes.userID)
WHERE (transfertipsvotes.questionID = '1' AND transfertipsvotes.answerID = '1') GROUP BY users.userID
UNION
SELECT users.userID, users.name, users.email FROM users
INNER JOIN transfertipsvotes ON (users.userID = transfertipsvotes.userID)
WHERE (transfertipsvotes.questionID = '2' AND transfertipsvotes.answerID = '2') GROUP BY users.userID
UNION
SELECT users.userID, users.name, users.email FROM users
INNER JOIN transfertipsvotes ON (users.userID = transfertipsvotes.userID)
WHERE (transfertipsvotes.questionID = '3' AND transfertipsvotes.answerID = '2') GROUP BY users.userID";
But this just returns all users with one correct answer.
How do I make the correct query to select all users with the correct answers?
As far as I can see it now you need to use an INNER JOIN for each question, so each inner join will look like this:
INNER JOIN votes AS q1 ON (users.userID = q1.userID) AND q1.questionID = '1' AND q1.answerID ='1'
Repeat this for each question and you can check it.
If i understood you correctly, you want users who have answered all questions correct. In that case you should use INTERSECT instead of UNION
But for this you are hitting the table as many times as your questions. Its better to use OR clause in where "((question1 and Answer1) or (question2 and Answer2))". and at last do a group based on userid and get count of correct answer and fetch only those members whose has all correct answer.
Related
I have problem with using alias in where clause.
I have tables like this:
I store users and they can send messages to each other. Messages data is stored in social_messages table, with core_users_sender and core_users_receiver ids.
Now when user logs in system I want to show the list of only those users with which he/she had conversation.
(logged in core_users.id is 6)
I use this query and get ids of friends with which user had conversations without problem:
SELECT
messages.id,
messages.status,
messages.send_date,
IF(
core_users_sender = 6,
core_users_receiver,
core_users_sender
) as friend_id
FROM
social_messages messages
WHERE
messages.core_users_sender = 6
OR
messages.core_users_receiver = 6
GROUP BY
friend_id
But problem is that when I try to get data from core_users table with friend_id and and use query:
SELECT
messages.id,
messages.status,
messages.send_date,
IF(
core_users_sender = 6,
core_users_receiver,
core_users_sender
) as friend_id,
users.fullname
FROM
social_messages messages,
core_users users
WHERE
users.id = friend_id
AND
(
messages.core_users_sender = 6
OR
messages.core_users_receiver = 6
)
GROUP BY
friend_id
I get error because friend_id cant be used in where clause because its calculated in select
You can't uses aliases in the where clause. Use the original subquery
where users.id = IF(
core_users_sender = 6,
core_users_receiver,
core_users_sender
)
It is not allowable to refer to a column alias in a WHERE clause, because the column value might not yet be determined when the WHERE clause is executed.
I suggest you to reorder your query in this way :
SELECT
messages.id,
messages.status,
messages.send_date,
users.fullname,
IF(
messages.core_users_sender IS NOT NULL,
messages.core_users_receiver,
messages.core_users_sender
) as friend_id
FROM
social_messages messages
left join core_users users_sender
on users_sender.id = messages.core_users_sender
and messages.core_users_sender = 6
left join core_users users_receiver
on users_receiver.id = messages.core_users_receiver
and messages.core_users_receiver = 6
WHERE
users_sender.id IS NOT NULL OR users_receiver.id IS NOT NULL
You can alias your table and use it
SELECT messages.*, users.fullname
FROM
(SELECT
messages.id,
messages.status,
messages.send_date,
IF(
core_users_sender = 6,
core_users_receiver,
core_users_sender
) as friend_id
FROM
social_messages messages
WHERE
messages.core_users_sender = 6
OR
messages.core_users_receiver = 6
GROUP BY
friend_id) as `messages`
JOIN
core_users users
ON
users.id = messages.friend_id
I'm very new to SQL/MySQL and Stackoverflow for that matter, and I'm trying to create a query through iReport (though I don't have to use iReport) for SugarCRM CE. What I need is to create a report that displays the number of "Referrals", "Voicemails", "Emails", and "Call_ins" that are linked to a specific "user" (employee). The query I currently have set up works; however it is running through the data multiple times generating a report that is 200+ pages. This is the code that I am currently using:
SELECT
( SELECT COUNT(*) FROM `leads` INNER JOIN `leads_cstm` ON `leads`.`id` = `leads_cstm`.`id_c` WHERE (leadtype_c = 'Referral' AND users.`id` = leads.`assigned_user_id`) ),
( SELECT COUNT(*) FROM `leads` INNER JOIN `leads_cstm` ON `leads`.`id` = `leads_cstm`.`id_c` WHERE (leadtype_c = 'VM' AND users.`id` = leads.`assigned_user_id`) ),
( SELECT COUNT(*) FROM `leads` INNER JOIN `leads_cstm` ON `leads`.`id` = `leads_cstm`.`id_c` WHERE (leadtype_c = 'Email' AND users.`id` = leads.`assigned_user_id`) ),
users.`first_name`,users.`last_name`
FROM
`users` users,
`leads` leads
I would appreciate any guidance!
You want to use conditional summation. The following uses MySQL syntax:
SELECT sum(leadtype_c = 'Referral') as Referrals,
sum(leadtype_c = 'VM') as VMs,
sum(leadtype_c = 'Email') as Emails,
users.`first_name`, users.`last_name`
FROM users join
`leads`
on users.`id` = leads.`assigned_user_id` INNER JOIN
`leads_cstm`
ON `leads`.`id` = `leads_cstm`.`id_c`
group by users.id;
You can use COUNT with CASE for this:
SELECT u.first_name,
u.last_name,
count(case when leadtype_c = 'Referral' then 1 end),
count(case when leadtype_c = 'VM' then 1 end),
count(case when leadtype_c = 'Email' then 1 end)
FROM users u
JOIN leads l ON u.id = l.assigned_user_id
JOIN leads_cstm lc ON l.id = lc.id_c
GROUP BY u.id
To match your exact results, you should probably use an OUTER JOIN instead, but this gives you the idea.
A Visual Explanation of SQL Joins
i have problem with join table and use multiple conditions...
My code:
SELECT * FROM
(SELECT sid, MAX(info_date_add) AS max_info_date_add FROM skiresort GROUP BY sid) skiresort_max
INNER JOIN skiresort
ON
skiresort_max.sid = skiresort.sid AND
skiresort_max.max_info_date_add = skiresort.info_date_add
JOIN skiresort_theme_value
ON skiresort_theme_value.skiresort_id = skiresort.id
WHERE
skiresort_theme_value.skiresort_theme_id = '1' AND
skiresort_theme_value.skiresort_theme_id = '2' AND
skiresort_theme_value.skiresort_theme_id = '4'
GROUP BY skiresort.sid
ORDER BY skiresort.title_en
In this code, the conditions are in WHERE clausule. I also tried to put in into JOIN ON (...) but it also didn't work.
When i have only one condition it works. I read some articles about using OR instead of AND, it worked but not as i expected. I need to search only rows with certain IDs (multiple).
why not use this instead of many conditions.
WHERE
skiresort_theme_value.skiresort_theme_id in (1, 2,4)
GROUP BY skiresort.sid
HAVING COUNT(DISTINCT skiresort_theme_value.skiresort_theme_id) = 3
ORDER BY skiresort.title_en
when add condition to WHERE, condition must be from FROM tbl
add condition JOIN ON
Try this:
SELECT * FROM
(SELECT sid, MAX(info_date_add) AS max_info_date_add FROM skiresort GROUP BY sid) skiresort_max
INNER JOIN skiresort
ON
skiresort_max.sid = skiresort.sid AND
skiresort_max.max_info_date_add = skiresort.info_date_add
JOIN skiresort_theme_value
ON (skiresort_theme_value.skiresort_id = skiresort.id AND skiresort_theme_value.skiresort_theme_id = '1' AND skiresort_theme_value.skiresort_theme_id = '2' AND skiresort_theme_value.skiresort_theme_id = '4')
GROUP BY skiresort.sid
ORDER BY skiresort.title_en
Ok, I'm trying to base something similar off of this, but not quite getting it nailed: GROUP BY and ORDER BY
Basically, wanting a query to find the latest messages in each 'thread' between the current logged-in user and any other users, but via a flat (non-'threaded') table of messages:
messages {
id,
from_uid,
to_uid,
message_text,
time_added
}
Assuming the current user's uid is '1', and the latest message in each 'thread' could either be from that user, or to that user (the other party always denoted by thread_recipient):
SELECT a.*,thread_recipient
FROM messages a
JOIN (SELECT IF(from_uid = '1',to_uid,from_uid) AS thread_recipient,
MAX(time_added) AS recency
FROM messages
WHERE (from_uid = '1' OR to_uid = '1')
GROUP BY thread_recipient) b ON thread_recipient = (IF(a.from_uid = '1',a.to_uid,a.from_uid))
AND b.recency = a.time_added
ORDER BY a.time_added DESC
But I fear this ain't gonna work right, and maybe messages sent at the same time might end up being returned for the wrong user?
Is my WHERE condition misplaced?
Any wisdom much appreciated.
Here's an idea: take the UNION of the following two queries, then get
the maximum dates from the result.
SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
When you do the following:
SELECT MAX(time_added),other_party
FROM (SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
UNION
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
) MyMessages
GROUP BY other_party
You will get the most recent time associated with a message sent to
each person that user '1' is corresponding with. Then you can join the
results of that to the original messages table to get what you want:
SELECT Messages.*
FROM (SELECT MAX(time_added) AS MaxTime,other_party
FROM (SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
UNION
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
) MyMessages
GROUP BY other_party
)
JOIN Messages
ON (Messages.time_added = MyMessages.MaxTime AND
(Messages.to_uid = MyMessages.other_party AND Messages.from_uid = '1' OR
Messages.from_uid = MyMessages.other_party AND Messages.to_uid = '1')
)
Try this - I think it gives you what you are looking for more simply and efficiently.
SELECT latest_time = MAX(a.time_added, b.time_added)
FROM messages a, messages b
LEFT JOIN messages a1
ON a1.from_uid = a.from_id
-- find the case where the following doesn't exist
-- so you know there is nothing after b1
LEFT JOIN messages a2
ON a2.from_uid = a.from_id
AND a2.time_added > a1.time_added
LEFT JOIN messages b1
ON b1.to_uid = b.to_id
LEFT JOIN messages b2
ON b2.to_uid = b.to_id
AND b2.time_added > b1.time_added
WHERE a.from_id = '1'
AND b.to_id = '1'
AND c1.id IS NULL
AND c2.id IS NULL
ORDER BY a.time_added DESC
Ok, after comments - if id is autoincrement use it instead of message time. But you have propoer condition to ensure that messages will not be delivered to wrong persons.
There are two tables - incoming tours(id,name) and incoming_tours_cities(id_parrent, id_city) where id_parrent is id from first table.
Here is the query i wrote
SELECT t.cities
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '1'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '6'
And now, what is the question...
Why i can't write both conditions in single join?(i.e. i can, but it returns empty result.)
as i understand joins, when i wrote
JOIN incoming_tours_cities tc ON tc.id_parrent = t.id
it must return the list of rows where the condition is true. isn't it?
So why i can't write
SELECT t.cities
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc ON tc.id_parrent = t.id
AND tc.id_city = '1'
AND tc.id_city = '6'
And maybe there is more efficient method to rich same effect(because in my structure the count of conditions can be very big)
Thanks much
the value of tc.id_city cannot be both '1' and '6' simultaneously. I think you want an OR rather than an AND:
SELECT t.cities
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc ON tc.id_parrent = t.id
AND (tc.id_city = '1'
OR tc.id_city = '6')
Think of it this way. If you ask for rows from incoming_tour_cities for which the id_city value is '1' and is also at the same time '6', how many rows will you match?
What you really want is:
SELECT t.cities
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc ON tc.id_parrent = t.id
WHERE (tc.id_city = '1' OR tc.id_city = '6')
or, more compactly:
SELECT t.cities
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc ON tc.id_parrent = t.id
WHERE tc.id_city IN ('1', '6')
An alternative answer based on the user's clarification that the first query is the one he wants to duplicate.
Here is the only "short cut" way I know of doing this, where "short cut" means not performing two independent tests (using JOINs or EXISTs clauses):
SELECT t.cities
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc ON tc.id_parrent = t.id
WHERE tc.id_city IN ('1', '6')
GROUP BY t.cities HAVING COUNT(DISTINCT tc.id_city) > 2