I'm trying to create a simple poll function using php and sql.
I have three tables:
Questions
Which simply contains each question asked
question_id | question_text | created_at
Answers
Which contains each answer for each question
question_id | answer_id | answer_text
Answered Questions
Which records who has voted for each option
question_id | answer_id | user_ip
I'm trying to write a query which will return a single question (the most recent) along with all the possible answers to that question and finally a count of each answer to each question. I know I will have to use a GROUP BY clause and possible LEFT OUTER JOIN, but the exact syntax is eluding me atm.
Any advice would be greatly appreciated. Thanks.
This is very similar to the logic in this article http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/.
Essentially you need a subquery which selects the single record / question you are interested in, as well as an outer query to select the information related to that record that you are interested in
(I could post another SQL statement to add to the nice collection that have already been posted, but I thought I'd try and shed some light onto how the other posted queries work)
This query should work on most DBMSs:
select q.question_id, question_text, a.answer_id, a.answer_text, count(user_ip)
from questions q
inner join answers a on (q.question_id = a.question_id)
left join answered_questions aq on (a.question_id = aq.question_id
and a.answer_id = aq.answer_id)
where created_at = (select max(created_at)
from questions
)
group by q.question_id, a.answer_id, q.question_text, a.answer_text
Assuming you're usnig MySQL:
SELECT q.* ,
(
SELECT COUNT(*)
FROM answered_questions aq
WHERE aq.answer_id = a.answer_id
AND aq.question_id = q.question_id
) AS votes
FROM (
SELECT *
FROM question
ORDER BY
created_at DESC
LIMIT 1
) q
LEFT OUTER JOIN
answers a
ON a.question_id = q.question_id
SELECT
questions.question_id,
questions.question_text,
answers.answer_id,
answers.answer_text,
COUNT(answered_questions.user_ip)
FROM
questions,answers,
answered_questions
WHERE
questions.question_id=answers.question_id
AND
questions.question_id=
(SELECT
question_id
FROM questions
ORDER BY questions.created_at
LIMIT 1
)
AND
answered_questions.question_id=questions.question_id
GROUP BY
questions.question_id
should work (although I haven't tested it).
Related
I want to fetch and display a limited amount of questions that hasn't been answered yet by the logged in user only.
I already have this block of code, but I can't seem to find out how to select it distinctly for a certain logged in user.
SELECT
a.*
FROM
questions as a
LEFT JOIN
questions_answers as b
ON (a.q_id = b.q_id)
WHERE
b.q_id IS NULL
AND b.user_id = 2
ORDER BY
RAND() LIMIT 10
assuming "2" is a sample user ID of the logged in user.
The "AND b.user_id = 2" is where I'm stuck.
I'll appreciate any help.
UPDATE:
Here's the table structure
Questions Table
q_id
question
Questions_Answers Table
ans_id
q_id
user_id
UPDATE:
I have already answered this question and added it below. Thank you to everyone who suggested. I'll take your advice seriously as well. I'll appreciate it if you will upvote my answer if you have tried it and get what I meant. :)
You can use left join with
SELECT a.*
FROM questions as a
LEFT JOIN questions_answers as b ON (a.q_id = b.q_id)
WHERE b.q_id IS NULL
AND b.user_id = 2
Please check below link How to select all records from one table that do not exist in another table?
I am little bit confused about your tables structure however i tried to answer it assuming you are storing answers and answering users_id in answers table -
Update: Thanks for providing table structure please see below update query.
SELECT questions.*, questions_answers.*
FROM questions
LEFT JOIN questions_answers ON questions.q_id = questions_answers.q_id
WHERE questions_answers.user_id <> '2'
OR
SELECT questions.*, questions_answers.*
FROM questions
LEFT JOIN questions_answers ON questions.q_id = questions_answers.q_id
WHERE NOT(questions_answers.user_id = '2')
And so, after a few trials (thanks to everyone who posted their suggestions), I was able to manage to get the data I am wanting for using the following block of code. :)
SELECT
a.*
FROM
questions as a
LEFT JOIN
questions_answers as b
ON (a.q_id = b.q_id) AND b.user_id = 2
WHERE
b.q_id IS NULL
ORDER BY RAND()
LIMIT 10
Sharing this so everyone who stumbles down on my post will get the correct answer. I'll appreciate if you will upvote this one if you have tried the code and got the answer. :)
SELECT
a.*
FROM
questions as a
WHERE
a.q_id not in(select q_id from questions_answers where user_id = 2)
ORDER BY
RAND() LIMIT 10
You can achieve this by simple inner query. I hope this will help you.
sqlfiddle : http://sqlfiddle.com/#!9/fee4ba/8
Or
SELECT * FROM (SELECT
a.* ,b.ans_id
FROM
questions as a
left JOIN
questions_answers as b
ON (a.q_id = b.q_id) AND b.user_id = 2 ) as c
WHERE c.ans_id IS null
ORDER BY
RAND() LIMIT 10
I've a project that create a q&a website.
I want to show questions by these conditions.
1. Show by the latest question, yeah i know just order by created desc.
2. Show and sort questions by most answers.
3. Show and sort questions by most voted. (like most answers) example.
4. Show questions where unanswered. example
And here is my tables structure in database.
TABLE question
COLUMNS
q_id (primary key)
userid
title
content
created
TABLE answer
COLUMNS
a_id (primary key)
userid
q_id
content
created
TABLE vote
COLUMNS
userid
q_id
created
And each tables it can have a million of rows.
For my 4 questions above I'm trying these SQL(s).
1 Show by the latest question. (solved)
select * from question order by created desc
2 Show and sort by most answers. (seems to slow)
SELECT q.*, COUNT(a.id) as answerCount
FROM question q
LEFT JOIN answer a
ON (q.q_id = a.q_id)
ORDER BY answerCount DESC
3 Show and sort by most voted. (seems to slow).
SELECT q.*, COUNT(v.id) as voteCount
FROM question q
LEFT JOIN vote v
ON (q.q_id = v.q_id)
ORDER BY voteCount DESC
4 Show questions where unanswered. (seems to slow)
SELECT q.*
FROM question q
LEFT JOIN answer a
ON p.q_id = a.q_id
WHERE a.q_id IS NULL ORDER BY q.created DESC
Note: If i use INNER JOIN the rows where count = 0 will not be selected.
As I think, The other websites are commonly have field to count answers and votes already? To make it fast and should i change to this or they have some algorithm which no need to count answer and vote in question table?
TABLE question
COLUMNS
q_id (primary key)
userid
title
content
created
answer_count
votes_count
Help or advice will be truly appreciated.
You can try re-writing your queries, but as MySQL is known for preferring joins over more straight-forward ways, they are not likely to be faster. Here are some queries you can try:
Show and sort by most answers. Use GROUP BY and COUNT(*) to make it plain what you do.
SELECT q.*, COUNT(*) as answerCount
FROM question q
LEFT JOIN answer a ON a.q_id = q.q_id
GROUP BY q.q_id
ORDER BY answerCount DESC;
Show and sort by most answers. Count in a sub-query.
SELECT q.*, (select count(*) from answers a where a.q_id = q.q_id) as answerCount
FROM question q
ORDER BY answerCount DESC;
Show and sort by most answers. Count in a derived table query.
SELECT q.*, a.answerCount
FROM question q
LEFT JOIN (select q_id, count(*) as answerCount from answers group by q_id) a
ON a.q_id = q.q_id
ORDER BY a.answerCount DESC;
Show questions where unanswered. I.e. where no answer EXISTS:
SELECT q.*
FROM question q
WHERE NOT EXISTS (select * from answer a where a.q_id = q.q_id)
ORDER BY q.created DESC;
However, as mentioned, these more straight-forward queries are not necessarily faster. Well, you can give them a try anyhow.
So if re-writing the queries doesn't speed things up, then, yes you can add an answer and a vote count to your question table. This is certainly redundant, but if requirements make such a step necessary, then take it.
Background Information
I have the following table structure:
Participants - id, email, organisation_type_id, job_role_id
Answers - id, participant_id, question_id, answer
Questions - id, question, question_category
There are two other tables, organisation types and job roles which just have an id and a name which are referred to in the above tables.
The tables hold data from when someone fills in a questionnaire (each question having a yes or no answer). Each of the questions also falls into one of two categories (denoted by the question_category field).
When someone completes the questionnaire, it creates a record in the Participants table and for each question it creates a record in the answers table.
The Problem
I want to count the yes answers and the no answers for each question, but based on a particular organisation type (which is held in the participants table).
So for example, if I want to know how many people voted yes and how many votes no who are part of organisation type x, I'd want a query like:
Count all answers to each question, where the participant has a organisation_type_id of x, group by answer
To make it a little more confusing, I also want the row to be included even if there are no answers for that particular question yet. For example, I might have answers for question id x, but none from a participant who is part of organisation_type_id y. I'd want the question returned as a row, but with 0 in the 'answer count' column.
Is my table structure the problem here or is it just a really confusing query? So far I'm using the following query, and then looping over the results with PHP to check if it's part of the organisation or job role that I want, but ideally I'd like to do it all in MySQL.
SELECT * FROM `questions`
JOIN `answers` ON `answers`.`question_id` = `questions`.`id`
JOIN `participants` ON `participants`.`id` = `answers`.`participant_id`
Thanks in advance!
Try this,
SELECT questions.id
,questions.question
,count(answers.id) as totalAns
,Sum(Case When participants.id is not null Then 1 Else 0 End) as WithPart
,Sum(Case When answers.answer = 'Yes' Then 1 Else 0 End) as YesAns
,Sum(Case When answers.answer = 'No' Then 1 Else 0 End) as NoAns
FROM questions
left JOIN answers ON answers.question_id = questions.id
left JOIN participants ON participants.id = answers.participant_id
and participants.organisation_type_id = 'x'
group by questions.id,questions.question
if you want answer for questions and questions without answer you must select from question inner join answer. Below query give you questions with answer yes or no answer:
select p.id, a.answer
from Participants p
inner join Answers a ON p.id = a.participant_id
where a.answer = 'yes' or a.answer = null
You want all questions. So select from questions. You want all answers to the question given by certain participants. So outer join the answers by these criteria. To get both counts (for yes and no) in one record sum them, rather than counting records.
select
q.id,
sum( case when a.answer = 'yes' then 1 ) as yes,
sum( case when a.answer = 'no' then 1 ) as no
from questions q
left outer join answers a on a.question_id = q.question_id and a.participant_id in
(
select p.id
from participants p
where p.organisation_type_id = 'x'
)
group by q.id
order by q.id;
I have a question about MySQL table.
I have 2 tables (users (user_id and other rows) and answers (id, answer_id and user_id))
I would like to check, which questions the user hasn't answered (for example, in answers table exists 5 rows - 4,6,8,1,3 (but questions are 10), I would like to get out from database values 2,5,7,9,10).
How to write a query like this?
I've tried with JOIN, but nothing was successful at all!
Assuming that you have a questions and an answers table, this is the standard TSQL solution:
SELECT Q.QUESTION_ID
FROM QUESTIONS Q LEFT JOIN ANSWERS A ON Q.QUESTION_ID = A.QUESTION_ID
WHERE A.QUESTION_ID IS NULL
Or use LEFT JOIN, it's faster.
SELECT q.id
FROM question q
LEFT JOIN answers a
ON a.question_id = q.id
WHERE a.id IS NULL
not sitting in front of a mySQL DB but it should be something to the point of (you didn't tell us where your questions are listed so I put in a placeholder) It also seems like your answer table HAS to have or should have a link to the question_id it is answering. If I made any incorrect assumptions please let me know and I will edit as needed.
Select question_id from question_table
where question_id not in (select question_id from answers)
I suppose you've got a QUESTION table:
select *
from question
where not exists(
select 'x'
from answer
where answer.question_id = question.id
)
If you haven't got a QUESTION table, IMHO there's no solution
I have 2 tables:
The question table with the following structure:
id
title
userid
date
and answers table with the following structure:
id
idquestion
userid
message
date
I want to show all the questions and the latest answer to that question.
For example, if we have 5 questions, I would like to get something like this:
id title message messagedate
1 qs 1 mess 1 2010-11-18
2 qs 2 mess 2 2010-11-19
3 qs 3 mess 3 2010-11-20
4 qs 4 mess 4 2010-11-21
My query so far:
SELECT q.id, qa.id as answerid, title, qa.message
FROM `questions` q
INNER JOIN questions_answers qa
ON q.id = qa.idquestion
GROUP BY q.id
ORDER BY q.id, answerid DESC
But it doesn't work correctly, it groups by the question id(removing all the other columns messages, leaving only the first message - so the order by is useless)
Any help appreciated. Thanks
The old problem. Here's the solution:
http://dev.mysql.com/doc/refman/5.1/en/example-maximum-column-group-row.html
In your case:
SELECT q.id, qa.id as answerid, title, qa.message
FROM questions q
JOIN questions_answers qa ON q.id = qa.idquestion
LEFT JOIN questions_answers qa2 ON qa.idquestion = qa2.idquestion AND qa.date < qa2.date
WHERE qa2.idquestion IS NULL
(The idea is to split the problem in two operations: One join from questions to answers and then use the methods from the MySQL article.)
Well you could approach it a different way. You are using an inner join, which means you won't show questions with no answer anyway, so search for max answer grouped by question id, and join questions table to get the title.
SELECT
q.id, qa.id as answerid, q.title, qa.message
FROM
questions q
INNER JOIN question_answers qa ON q.id = qa.idquestion AND qa.id IN (SELECT MAX(id) FROM question_answers WHERE idquestion = q.id)
GROUP BY
q.id
ORDER BY
q.id DESC