Getting count byjoining multiple tables - mysql

I have 3 tables
1)question
2)options
3)answers
Table 1 contains list of multiple choice questions. Table 2 contains multiple choices for the question.
Consider an example, I have the question "Which game do you like most?"
It is stored in table 1 with id 1. For this question there are 3 choices in table 2; as "cricket", "football", "tennis" with ids 1,2 & 3.
When a user answer this question the question id, and option id are stored to the third table as if he select football, entry in table 3 is question id and option id.
If another user select same option new entry is stored in table 3.
My need is that I want to get the count of each options in table 3.
Consider 10 users select cricket, 15 users select football, no user select tennis, so I need count as 10,15,0 with its corresponding option id
Table name: questions
--------------------------------
| id | question |
--------------------------------
| 1 | which game u like most |
Table Name: options
------------------------------------------------
| id | qid | option_name |
------------------------------------------------
| 1 | 1 | cricket |
------------------------------------------------
| 2 | 1 | football |
------------------------------------------------
| 3 | 1 | tennis |
------------------------------------------------
Table Name: answers
--------------------------------------------
| id | qid | optionId |
--------------------------------------------
| 1 | 1 | 3 |
---------------------------------------------
| 2 | 1 | 3 |
----------------------------------------------
| 3 | 1 | 2 |
----------------------------------------------
The above table means that, 2 people choose tennis, 1 people choose football and no one choose cricket. So I need result table as
------------------------------------------------------
| id | question | option_name | count |
------------------------------------------------------
| 1 | which game u like most | cricket | 0 |
-------------------------------------------------------
| 2 | which game u like most | football | 1 |
-------------------------------------------------------
| 3 | which game u like most | tennis | 2 |
-------------------------------------------------------
But when I tried, I didnt get the count for cricket, because no one selected cricket.I must get count of cricket as 0. Can any one help me solve the issue?
My sql code is
SELECT count(an.optionId) count , op.option_name, q.question from
questions q, options op, answers an where q.id=1
and q.id=op.qid
and op.id=an.optionId
group by q.question, op.option_name

Just use a LEFT JOIN and COALESCE() :
SELECT COALESCE(count(an.optionId),0) as count , op.option_name, q.question from
questions q
INNER JOIN options op
ON(q.id=op.qid )
LEFT OUTER JOIN answers an
ON(p.id=an.optionId)
where q.id=1
group by q.question, op.option_name
Please avoid the use of implicit join syntax(comma separated ) and use only the correct syntax of a join! LEFT JOIN with implicit syntax getting more hard to read and more easy to make mistakjes.

Related

MySQL - join multiple mapped tables and count records with different mapping conditions

It's the 3rd day I'm trying to write a MySQL query. Did lots of search, but it still doesn't work as expected. I'll try to simplify tables as much as possible
System has tkr_restaurants table:
restaurant_id | restaurant_name
1 | AA
2 | BB
3 | CC
Each restaurant has a division assigned (tkr_divisions table):
division_id | restaurant_id | division_name
1 | 1 | AA-1
2 | 1 | AA-2
3 | 2 | BB-1
Then there are meals in tkr_meals_to_restaurants_divisions table, where each meal can be assigned (mapped) to whole restaurant(s) and/or specific division(s). If meal is mapped to restaurant, all restaurant's divisions should see it. If meal is mapped to division(s), only specific division(s) should see it.
meal_id | mapped_restaurant_id | mapped_division_id
1 | 1 | NULL
2 | NULL | 1
3 | NULL | 2
I need to display a list of restaurants and number of meals mapped to it depending on user permissions.
Example 1: if user has permissions to access whole restaurant_id 1 and restaurant_3 (and no specific divisions), then list should be:
AA | 3
CC | 0
(because user can access meals mapped to restaurant 1 + all its division, and restaurant 3 + all its divisions (even if restaurant 3 has no divisions/meals mapped))
Example 2: if user has permissions to access only division_id 1, then list should be:
AA | 1
(because user can only access meals mapped to division 1).
The closest query I could get is:
Example 1:
SELECT *,
(SELECT COUNT(DISTINCT meal_id)
FROM
tkr_meals_to_restaurants_divisions
WHERE
tkr_meals_to_restaurants_divisions.mapped_restaurant_id=tkr_restaurants.restaurant_id
OR tkr_meals_to_restaurants_divisions.mapped_division_id=tkr_divisions.division_id)AS total_meals
FROM
tkr_restaurants
LEFT JOIN
tkr_divisions
ON tkr_restaurants.restaurant_id=tkr_divisions.restaurant_id
WHERE
tkr_restaurants.restaurant_id IN (1, 3)
OR tkr_restaurants.restaurant_id IN (
SELECT restaurant_id
FROM tkr_divisions
WHERE division_id IN (NULL)
)
GROUP BY
tkr_restaurants.restaurant_id
ORDER BY
tkr_restaurants.restaurant_name
However, result was:
AA | 2
CC | 0
I believe I'm greatly over-complicating this query, but all the simpler queries I wrote produced even more inaccurate results.
What about this query:
SELECT
FROM tkr_restaurants AS a
JOIN tkr_divisions AS b
ON a.restaurant_id = b.restaurant_id
LEFT OUTER JOIN tkr_meals_to_restaurants_divisions AS c
ON (c.mapped_restaurant_id = a.restaurant_id OR c.mapped_division_id = b.division_id)
As a Base four your further work. It combine all information into one table. If you add e.g. this:
WHERE a.restaurant_id IN (1, 3)
the result will be
| restaurant_id | restaurant_name | division_id | restaurant_id | division_name | meal_id | mapped_restaurant_id | mapped_division_id |
|---------------|-----------------|-------------|---------------|---------------|---------|----------------------|--------------------|
| 1 | AA | 1 | 1 | AA-1 | 1 | 1 | (null) |
| 1 | AA | 2 | 1 | AA-2 | 1 | 1 | (null) |
| 1 | AA | 1 | 1 | AA-1 | 2 | (null) | 1 |
| 1 | AA | 2 | 1 | AA-2 | 3 | (null) | 2 |
just count the distinct meal ids with COUNT(DISTINCT c.meal_id) and take the restaurant name to get AA: 3 for your example 2
I used a sqlfiddle: http://sqlfiddle.com/#!9/fa2b78/18/0
[EDIT]
Change JOIN tkr_divisions AS b to LEFT OUTER JOIN tkr_divisions AS b
Change SELECT * to SELECT a.restaurant_name, COUNT(DISTINCT c.meal_id)
Add a GROUP BY a.restaurant_name at the end.
Update the SQL Fiddle (new link)

Getting count of same fileds in Table SQL

I have 3 tables
1)question
2)options
3)answers
Table 1 contains list of multiple choice questions. Table 2 contains multiple choices for the question.
Consider an example, I have the question "Which game do you like most?"
It is stored in table 1 with id 1. For this question there are 3 choices in table 2; as "cricket", "football", "tennis" with ids 1,2 & 3.
When a user answer this question the question id, and option id are stored to the third table as if he select football, entry in table 3 is question id and option id.
If another user select same option new entry is stored in table 3.
My need is that I want to get the count of each options in table 3.
Consider 10 users select cricket, 15 users select football, no user select tennis, so I need count as 10,15,0 with its corresponding option id
Table name: questions
--------------------------------
| id | question |
--------------------------------
| 1 | which game u like most |
Table Name: options
------------------------------------------------
| id | qid | option_name |
------------------------------------------------
| 1 | 1 | cricket |
------------------------------------------------
| 2 | 1 | football |
------------------------------------------------
| 3 | 1 | tennis |
------------------------------------------------
Table Name: answers
--------------------------------------------
| id | qid | optionId |
--------------------------------------------
| 1 | 1 | 3 |
---------------------------------------------
| 2 | 1 | 3 |
----------------------------------------------
| 3 | 1 | 2 |
----------------------------------------------
The above table means that, 2 people choose tennis, 1 people choose football and no one choose cricket. So I need result table as
------------------------------------------------------
| id | question | option_name | count |
------------------------------------------------------
| 1 | which game u like most | cricket | 0 |
-------------------------------------------------------
| 2 | which game u like most | football | 1 |
-------------------------------------------------------
| 3 | which game u like most | tennis | 2 |
-------------------------------------------------------
But when I tried, I didnt get the count for cricket, because no one selected cricket.I must get count of cricket as 0. Can any one help me solve the issue?
My sql code is
SELECT count(an.optionId) count , op.option_name, q.question from
questions q, options op, answers an where q.id=1
and q.id=op.qid
and op.id=an.optionId
group by q.question, op.option_name
okay for instance, i will try to assume your situation;
3 tables:
question(question_id, question,..)
question_option(question_id,option_id,option,..) note: question_id is fk
user_answer(question_id,option_id,..)
select count(ua.option_id) count, qo.option,
q.question_name
from question q, uestion_option qo, user_answer ua
where q.question_id = ua.question_id
and q.question_id = qo.question_id
and qo.option_id = ua.option_id
group by q.question_name, qo.option

Match data against one column in mysql

Here is the sqlFiddle
I want to filter the users who have selected entities ,So if I want to filter user with entity say entity having ids "1" and "3" I hope to get the users which have both of these entities.
No of entities selected can vary in number .
Query I am using is
SELECT user_id from user_entities where entity_id IN(1,3)
but for obvious reason it is returing me result as
+----+-----------+---------+--------+
| ID | ENTITY_ID | USER_ID | STATUS |
+----+-----------+---------+--------+
| 1 | 1 | 3 | 1 |
| 2 | 3 | 3 | 1 |
| 7 | 1 | 2 | 1 |
| 29 | 3 | 1 | 1 |
+----+-----------+---------+--------+
So I will apply distinct to it it will give me user id with ids 1,2,3 but I only want user 3 as this is the only user having both entities .
What can be modified to get the exact results
You could join the table to itself specifying both IDs as part of the join condition:
SELECT e1.user_id
FROM user_entities e1
INNER JOIN user_entities e2
ON e1.user_id = e2.user_id AND
e1.entity_id = 1 AND
e2.entity_id = 3;

Writing a MySQL query that counts entries uniquely

This is my table structure-
TABLE : T_LOG
---------------------------------------------------
| ID | AREA | USER_ID | DATE
---------------------------------------------------
| 1 | AREA1 | 5 | 2000-05-17
---------------------------------------------------
| 2 | AREA1 | 5 | 2002-12-12
---------------------------------------------------
| 3 | AREA2 | 5 | 2003-02-19
---------------------------------------------------
| 4 | AREA1 | 5 | 2006-05-22
---------------------------------------------------
| 5 | AREA2 | 5 | 2006-07-29
---------------------------------------------------
| 6 | AREA3 | 5 | 2009-05-07
---------------------------------------------------
In this table USER_ID 5 has been to several AREAs at several DATEs.
I want to pick how many (uniquely) AREAs the particular USER_ID has been to so far.
The following query
SELECT COUNT(*) FROM T_LOG WHERE USER_ID = 5 GROUP BY 'AREA'
returns 6 as in 6 entries. But I want it to return 3 as in 3 Areas uniquely (AREA1, AREA2, AREA3)
How do I correct this query?
You can use count (distinct):
SELECT COUNT(DISTINCT AREA) FROM T_LOG WHERE USER_ID = 5
Your actual problem is that you have specified Area column as a value in the GROUP BY clause (i.e. GROUP BY 'Area'). Which should be without single quotes. (i.e. GROUP BY Area)
So try this query:
SELECT COUNT(*) FROM T_LOG WHERE USER_ID = 5 GROUP BY AREA
See this SQLFiddle
Alternatively you can directly use COUNT(DISTINCT Area) as already mentioned in other answers (which one is more preferable).
SELECT COUNT(DISTINCT AREA), USER_ID FROM T_LOG WHERE USER_ID = 5

Find rows that hasn't a defined relation with a selected row in other table?

I have two table like following ones:
users
-----
id | name
_________
1 | mert
2 | ersin
3 | faruk
friends
-------
id | follower | following
_________________________
1 | 2 | 3 |
2 | 3 | 1 |
__________________________
I want to find people who don't follow the selected person.
For example:
get_people_not_follow(2) // "ersin"
Result: array(array(1, 'mert'), array(3, 'faruk'));
get_people_not_follow(1) // "mert"
Result: array(array(2, 'ersin'));
Thanks for your help.
SELECT users.id, name
FROM users LEFT JOIN friends ON (following = users.id AND follower = ##)
WHERE friends.id IS NULL
Where ## is the ID you are interested in.