mysql query for multiple fields - mysql

I am using mysql for survey answers.
the schema of the survey table is as follows:
id | rating1 | rating2 | rating3 | rating4 | .... | rating20 |
1 10 10 2 8 .... 4
2 8 8 8 5 .... 7
As you can see, there's rating scores (from 1 to 10) inserted into rating1 - rating20 fields.
I can easily find biggest or smallest scores from rating(1-20) fields for each row using this query: "SELECT greatest(rating1, rating2 .. rating20) FROM TBL_SURVEY WHERE id=1" which returns 10 for id 1.
But I don't know that greatest score belongs which field. And I like to count distnct rating scores. How many 10s or any other scores from rating1-rating20 fields for id 1?
Is there mysql queries for this? or Is there a way to get what I want using php?
Any help would be very appreciated...

I'm going to suggest that you change your table design to something like this:
id | rating_id | rating
1 | 1 | 10
1 | 2 | 10
1 | 3 | 2
1 | 4 | 8
etc.
With this improved and normalized design, we can find the max rating and its corresponding rating_id using a query like this:
SELECT t1.*
FROM ratings t1
INNER JOIN
(
SELECT id, MAX(rating) AS max_rating
FROM ratings
GROUP BY id
) t2
ON t1.id = t2.id AND
t1.rating = t2.max_rating
For your second question of e.g. how many 10s there are for id 1 we could use this:
SELECT COUNT(*)
FROM ratings
WHERE id = 1 AND rating = 10

Related

Search for multiple conditions on same column?

In SQL, how to select all rows that satisfy multiple AND conditions (not OR) of the same column?
Such as: "select all users who speak these 3 languages (language_id == 1 AND language_id == 2 AND language_id ==3)" where language_id is a column
id | user_id | language_id
--------------------------
1 | 1 | 1
2 | 2 | 1
3 | 2 | 2
4 | 3 | 1
5 | 4 | 1 << which users speak this language )
6 | 4 | 2 << AND speak this language ) => expected result: user_id == 4
7 | 4 | 3 << AND speak this language )
8 | 5 | 1
9 | 6 | 1
10 | 7 | 1
First select all users having the wanted languages, count the languages and then restrict the users to have the language count equal to the count of the wanted languages.
SELECT user_id
FROM (SELECT used_id,COUNT(*)
FROM [table_name]
WHERE language_id IN (1,2,3)
GROUP BY user_id
HAVING COUNT(*)=3
) i;
You have some ways to do that.
One simple way would be to create a view returning the user_id with the count for each language, for example:
CREATE VIEW myView
AS
SELECT DISTINCT T0.user_id
,(SELECT COUNT(*) FROM [myTable] WHERE user_id=T0.user_id AND language_id=1) AS L1
,(SELECT COUNT(*) FROM [myTable] WHERE user_id=T0.user_id AND language_id=2) AS L2
,(SELECT COUNT(*) FROM [myTable] WHERE user_id=T0.user_id AND language_id=3) AS L3
FROM [myTable] AS T0
GO
You should get a result like this:
Then, you only need to query this view, getting just the user_id where L1>0 AND L2>0 AND L3>0...
SELECT * FROM myView WHERE L1>0 AND L2>0 AND L3>0
Regards,

MySQL add avg of count by id to existing select with id

Im not even sure what the title of this question should be but lets start out with my data.
I have a table of users who have taken a few lessons while belonging to a particular training center.
lesson table
id | lesson_id | user_id | has_completed
----------------------------------------
1 | asdf3314 | 2 | 1
2 | d13saf12 | 2 | 1
3 | a33adff5 | 2 | 0
4 | a33adff5 | 1 | 1
5 | d13saf12 | 1 | 0
user table
id | center_id | ...
----------------------------------------
1 | 20 | ...
2 | 30 | ...
training center table
id | center_name | ...
----------------------------------------
20 | learn.co | ...
30 | teach.co | ...
I've written a small chunk but am now stuck as I don't know how to proceed. This statement gets the counted total of completed lessons per user. it then figures the average completed value from a center id. if two users belong to a center and have completed 3 lessons and 2 lessons it finds the average of 3 and 2 then returns that.
SELECT
FLOOR(AVG(a.total)) AS avg_completion,
FROM
(SELECT
user_id,
user.center_id,
count(user_id) AS total
FROM lesson
LEFT JOIN user ON user.id = user_id
WHERE is_completed = 1 AND center_id = 2
GROUP BY user_id) AS a;
The question I have is how do I loop through the training centers table and also append average data from similar select statement as above to each center that is queried. I cant seem to pass the center id down to the subquery so there must be a fundamentally different way to achieve the same query but also loop through training centers.
An example of desired result:
center.id | avg_completion | ...training center table
-----------------------------------------------------
20 | 2 | ...
Your main query needs to select a.center_id and then use GROUP BY center_id. You can then join it with the training_center table.
SELECT c.*, x.avg_completion
FROM training_center AS c
JOIN (
SELECT
a.center_id,
FLOOR(AVG(a.total)) AS avg_completion
FROM (
SELECT
user_id
user.center_id,
count(*) AS total
FROM lesson
JOIN user ON user.id = user_id
WHERE is_completed = 1 AND center_id = 2
GROUP BY user_id) AS a
GROUP BY a.center_id) AS x
ON x.center_id = c.id
If I understand correctly:
select u.center_id, count(*) as num_users,
sum(l.has_completed) as num_completed,
avg(l.has_completed) as completed_ratio
from lesson l join
user u
on l.user_id = u.id
group by u.center_id

I need to select a result based on 2 registers from a relation tablet. How do I do that?

I have 3 tables:
Question (id, questionText)
QuestionCategory (id, categoryName)
Question_QuestionCategory (questionId, categoryId)
Sample Data:
Table Question:
id | questionText
1 | 2 + 2 = ?
2 | 10 x 5 / 3 + 5 = ?
3 | USA is located in which continent?
Table QuestionCategory:
id | categoryName
1 | Easy
2 | Hard
3 | Math
4 | Geography
Table Question_QuestionCategory:
questionId | categoryId
1 | 1
1 | 3
2 | 2
2 | 3
3 | 1
3 | 4
The Question_QuestionCategory table is a relation table that stores the foreign keys from the question and questionCategory tables.
My problem is: I need a select that returns to me a question that has the Hard and Math categories at the same time (the question with id 2 in this case). How can I do that?
You can do that by using aggregation an checking if the distinct count of categories is equal to the number of categories you asked for. To only get one row as a result you can use LIMIT.
SELECT q.id,
q.text
FROM question q
INNER JOIN question_questioncategory qc
ON qc.question = q.id
INNER JOIN questioncategory c
ON c.id = qc.categoryid
WHERE c.categoryname IN ('Hard',
'Math')
GROUP BY q.id,
q.text
HAVING count(DISTINCT c.categoryname) = 2
LIMIT 1;

MySQL group by with left join

I am trying to do a very complex query (at least extremely complex for me not for YOU :) )
I have users and comments table.
SQL Fiddle: http://sqlfiddle.com/#!9/b1f845/2
select user_id, status_id from comments where user_id in (2,3);
+---------+-----------+
| user_id | status_id |
+---------+-----------+
| 2 | 10 |
| 2 | 10 |
| 2 | 10 |
| 2 | 7 |
| 2 | 7 |
| 2 | 10 |
| 3 | 9 |
| 2 | 9 |
| 2 | 6 |
+---------+-----------+
If I use
select user_id, status_id from comments where user_id in (2,3)
It returns a lot of duplicate values.
What I want to get if possible.
If you see status_id = 10 has user_id= 2,3 and 4 and 2 multiple times.
So from here I want to get maximum of latest user_id (unique) so for example,
it will be user_id = 4 and 2 now the main complex part. I now want to get users information of user_id= 4 and 2 in one column so that at the end I can get something like this
status_id | userOneUserName | userTwoUserName
10 sadek4 iamsadek2
---------------------------------------------
7 | iamsadek2 | null
---------------------------------------------
9 . | iamsadek2 | sadek2
---------------------------------------------
6 | iamsadek2 | null
How can I achieve such a complex things.
Currently I have to do it using application logic.
Thank you for your time.
I think this might be what you literally want here:
SELECT DISTINCT
status_id,
(SELECT MAX(user_id) FROM comments c2 WHERE c1.status_id = c2.status_id) user_1,
(SELECT user_id FROM comments c2 WHERE c1.status_id = c2.status_id
ORDER BY user_id LIMIT 1 OFFSET 1) user_2
FROM comments c1
WHERE user_id IN (2,3);
Demo (your update Fiddle)
We can use correlated subqueries to find the max user_id and second-to-max user_id for each status_id, and then spin each of those out as two separate columns. Using a GROUP_CONCAT approach might be preferable here, since it would also allow you to easily accommodate any numbers of users as a CSV list.
Also, if you were using MySQL 8+ or greater, then we could take advantage of the rank analytic functions, which would also be easier.
select status_id, GROUP_CONCAT(distinct(user_id) SEPARATOR ',')
from comments
group by status_id
I would suggest using GROUP BY and GROUP_CONCAT, e.g. like so:
SELECT status_id, GROUP_CONCAT(userName) AS users, GROUP_CONCAT(DISTINCT c.user_id) AS user_ids
FROM (
SELECT DISTINCT status_id, user_id FROM comments WHERE user_id in (2,3)
) c
JOIN users u ON (c.user_id = u.id)
GROUP BY status_id
ORDER BY status_id DESC

How to get total occurrence of a value within its own query?

Let's say we have this query
SELECT * FROM table
And this result from it.
id | user_id
------------
1 | 1
------------
2 | 1
------------
3 | 2
------------
4 | 1
How could I get the count of how often a user_id appears as another field (without some major SQL query)
id | user_id | count
--------------------
1 | 1 | 3
--------------------
2 | 1 | 3
--------------------
3 | 2 | 1
--------------------
4 | 1 | 3
We have this value currently in code, but we are implementing sorting to this table and I would like to be able to sort in the SQL query.
BTW if this is not possible without some major trick, we are just going to skip sorting on that field.
You'll just want to add a subquery on the end, I believe:
SELECT
t.id,
t.user_id,
(SELECT COUNT(*) FROM table WHERE user_id = t.user_id) AS `count`
FROM table t;
SELECT o.id, o.user_id, (
SELECT COUNT(id)
FROM table i
WHERE i.user_id = o.user_id
GROUP BY i.user_id
) AS `count`
FROM table o
I suspect this query as not being a performance monster but it should work.