简体   繁体   中英

MySQL join query, can't figure it out

I have two tables: questions and questions_lookup . Users vote if it's a good question or not to put on the site.

table: questions
    id
    question
    date_created
table: questions_lookup
    id
    question_id // (id linked to questions table)
    user_id // (the id of the user, I store this in a session variable called $me)
    show // (1 or 0, show or don't show)

I would like to have a php page that pulls all the questions from the questions table ordered by their date_created and then display if the user has answered it or not. When I attempt to do any joins, I end up having duplicate questions show because it will pull other user's answers.

So if there are 10 questions. And a particular user has only answered 3. We still display all 10 questions, but mark the ones that they've answered.

So I essentially want to display something like:

Question 1
Question 2 (answered)
Question 3 (answered)
Question 4
Question 5
Question 6
Question 7 (answered)
Question 8
Question 9
Question 10 

I've tried:

SELECT * FROM questions
RIGHT JOIN questions_lookup
ON (questions.id = questions_lookup.question_id)
WHERE questions_lookup.user_id = '$me'
ORDER BY questions.date_created DESC

Something like this, assuming there can only be one record per user per question in questions_lookup .

select
  q.*,
  case when ql.question_id is null then
    'no'
  else
    'yes'
  end as user_has_answered
from
  questions q
  left join questions_lookup ql 
    on ql.question_id = q.id
    and ql.user_id = 5 /* User id of current user */

The trick is to query all questions and left join the questions_lookup . By adding the user_id to the join condition, you will leave out records of other users, while still returning the questions that don't have a record for the current user. If you move ql.user_id = 5 to a where clause, the query will no longer work, because it would effectively turn your left join into an inner join.

[edit]

I see you have added your query. Two mistakes there. Right join should be left join, because you always want to have a record on the left (questions), and optional records on the right (lookup). Also, the condition should not be in the where clause.

How about :

SELECT questions.*, max(questions_lookup.show) AS show 
FROM questions 
LEFT JOIN questions_lookup ON questions_lookup.question_id=questions.id 
WHERE (questions_lookup.user_id='youruserid' OR questions_lookup.user_id IS NULL) 
GROUP BY questions.id 
ORDER BY questions.date_created ASC

Then in your results, show=1 means the user has answered.

SELECT q.*, 
       l.user_id,
       l.show,
       IF(l.question_id IS NULL,'','answered') as answered
  FROM questions q LEFT JOIN
       questions_lookup l ON q.id = l.question_id AND
                             l.user_id = 5 <-- user id goes here
 ORDER BY q.date_created DESC

You can play with with the calculated answered column, depending on what output you really need for further processing:

IF(l.question_id IS NULL,'','answered') as answered <-- 'answered' if answered, empty string if not (like in your example)
IFNULL(l.question_id,0) as answered <-- question_id (if autogenerated unsigned  int will be > 0) if answered, 0-if not

or as GolezTrol suggeested

CASE WHEN ql.question_id IS NULL THEN 'no' ELSE 'yes' END as answered <-- yes if answered and no if not

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM