group Items by column and order by other column - mysql

I have table as below , I want to take latest rating for the client
basically user whenever updates rating, count will be incremented and a entry will be made in table. Table goes as below
-----------------------------------------------------
|_id| name | client_id | user_id | rating | count |
-----------------------------------------------------
|1 | Four | 1 | 1 | 4 | 1 |
|2 | three | 1 | 1 | 3 | 2 |
|3 | two | 1 | 1 | 2 | 3 |
|4 | five | 1 | 1 | 5 | 4 |
|5 | two | 1 | 2 | 2 | 1 |
|6 | three | 1 | 2 | 3 | 2 |
|7 | two | 2 | 1 | 2 | 1 |
|8 | three | 2 | 1 | 3 | 2 |
-----------------------------------------------------
For rating of client_id 1 I want out put like
-----------------------------------------------------
|_id| name | client_id | user_id | rating | count |
-----------------------------------------------------
|4 | five | 1 | 1 | 5 | 4 |
|6 | three | 1 | 2 | 3 | 2 |
-----------------------------------------------------
so far I tried SELECT * FROM test
where client_id = 1 group by client_id order by count desc;
but not getting expected result, any help??

You can use left join on the same table as
select t1.* from test t1
left join test t2 on t1.user_id = t2.user_id
and t1.client_id = t2.client_id
and t1._id < t2._id
where
t2._id is null
and t1.client_id = 1
order by t1.`count` desc;
Using un-correlated subquery you may do as
select t1.* from test t1
join (
select max(_id) as _id,
client_id,
user_id
from test
where client_id = 1
group by client_id,user_id
)t2
on t1._id = t2._id
and t1.client_id = t2.client_id
order by t1.`count` desc;
UPDATE : From the comment how to join another table into above , for this here is an example
mysql> select * from users ;
+------+------+
| _id | name |
+------+------+
| 1 | AAA |
| 2 | BBB |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from test ;
+------+-------+-----------+---------+--------+-------+
| _id | name | client_id | user_id | rating | count |
+------+-------+-----------+---------+--------+-------+
| 1 | four | 1 | 1 | 4 | 1 |
| 2 | three | 1 | 1 | 3 | 2 |
| 3 | two | 1 | 1 | 2 | 3 |
| 4 | five | 1 | 1 | 5 | 4 |
| 5 | two | 1 | 2 | 2 | 1 |
| 6 | three | 1 | 2 | 3 | 2 |
| 7 | two | 2 | 1 | 2 | 1 |
| 8 | three | 2 | 1 | 3 | 2 |
+------+-------+-----------+---------+--------+-------+
select t1.*,u.name from test t1
join users u on u._id = t1.user_id
left join test t2 on t1.user_id = t2.user_id
and t1.client_id = t2.client_id
and t1._id < t2._id
where
t2._id is null
and t1.client_id = 1
order by t1.`count` desc;
Will give you
+------+-------+-----------+---------+--------+-------+------+
| _id | name | client_id | user_id | rating | count | name |
+------+-------+-----------+---------+--------+-------+------+
| 4 | five | 1 | 1 | 5 | 4 | AAA |
| 6 | three | 1 | 2 | 3 | 2 | BBB |
+------+-------+-----------+---------+--------+-------+------+
Note that the join to users table is inner join and this will require all the user to be preset in users table which are in test table
If some users are missing in the users table then use left join this will have null values for the data selected from users table.

You may try something like
select _id, name, client_id, user_id, rating, max(count)
from clients
group by client_id

Try it
SELECT * FROM test
where client_id = 1
group by user_id
order by count desc

Related

mysql table ordering incorrect with group by and order by

table 1: forum_threads
+-----+------+-------+
| id | title| status|
+-----+------+-------+
| 1 | a | 1 |
| 2 | b | 1 |
| 3 | c | 1 |
| 4 | d | 1 |
| 5 | e | 1 |
| 6 | f | 1 |
+-----+------+-------+
table 2: forum_comments
+-----+----------+--------------------+
| id | thread_id| comment |
+-----+----------+--------------------+
| 1 | 4 | hai |
| 2 | 4 | hello |
| 3 | 2 | welcome |
| 4 | 2 | whats your name |
| 5 | 6 | how are you |
| 6 | 5 | how old are you |
| 7 | 5 | good |
+-----+----------+--------------------+
wanted output
+-----------+----------+-----------------+
| thread_id | title | comment_count |
+-----------+----------+-----------------+
| 5 | e | 2 |
| 6 | f | 1 |
| 2 | b | 2 |
| 4 | d | 2 |
+-----------+----------+-----------------+
my Query
SELECT forum_threads.*,forum_comments.*,count(forum_comments.id) as comment_count
FROM forum_comments
LEFT JOIN forum_threads ON forum_comments.thread_id = forum_threads.id
GROUP BY forum_threads.id
ORDER BY forum_comments.id desc
Here I am trying to get the titles by the latest comment.
when I give ORDER BY forum_comments.id this returns the wrong order.
I need to order by the latest comments in the forum_comments table.
this query returns the wrong order please help me to find out the correct order.
how could I solve this easily?
This query should give you the expected result:
select t2.thread_id, t1.title, t2.comment_count from forum_threads as t1,
(SELECT id, thread_id, count(comment) as comment_count from forum_comments group by thread_id) as t2
where t1.id = t2.thread_id order by t2.id desc;
Instead of using forum_threads.* and forum_comments.* can you give specific column names and try.
If that doesn't work you should try explicitly assigning primary and foreign keys.

How to get only one record in subquery for each record's max result

I have a user - course - exam database.
Table structures:
user table structure
+--------------------------------------------+
| user |
+--------------------------------------------+
| user_id | fullname | email |
+---------+--------------+-------------------+
| 1 | Test User 01 | test01#domain.com |
+---------+--------------+-------------------+
| 2 | Test User 02 | test02#domain.com |
+---------+--------------+-------------------+
| 3 | Test User 03 | test03#domain.com |
+---------+--------------+-------------------+
| 4 | Test User 04 | test04#domain.com |
+---------+--------------+-------------------+
course table structure
+-----------------------+
| course |
+-----------------------+
| course_id | title |
+-----------+-----------+
| 1 | Course 01 |
+-----------+-----------+
| 2 | Course 02 |
+-----------+-----------+
| 3 | Course 03 |
+-----------+-----------+
course_exam table structure (course can have one or more exam)
+----------------------------+
| course_exam |
+----------------------------+
| course_exam_id | course_id |
+----------------+-----------+
| 1 | 1 |
+----------------+-----------+
| 2 | 1 |
+----------------+-----------+
| 3 | 2 |
+----------------+-----------+
| 4 | 3 |
+----------------+-----------+
| 5 | 2 |
+----------------+-----------+
user_course_exam table structure (users can join one or more exam)
+---------------------------------------------------------------------------------------------------------------+
| user_course_exam |
+---------------------------------------------------------------------------------------------------------------+
| user_course_exam_id | course_exam_id | user_id | right_answer_total | wrong_answer_total | blank_answer_total |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 1 | 1 | 1 | 2 | 3 | 0 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 2 | 1 | 1 | 4 | 1 | 0 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 3 | 2 | 1 | 5 | 0 | 0 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 4 | 1 | 1 | 3 | 1 | 1 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
| 5 | 3 | 1 | 4 | 0 | 1 |
+---------------------+----------------+---------+--------------------+--------------------+--------------------+
I should prepare a report like below:
user_id
fullname
email
completed_course_total (course total having completed exams by user)
remaining_course_total
right_answer_total (Max right answer for best scored exam. Only one result should fetch for each course)
Expected report result
+-------------------------------------------------------------------------------------------------------------------+
| user_id | fullname | email | completed_course_total | remaining_course_total | right_answer_total |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
| 1 | Test User 01 | test01#domain.com | 2 | 1 | 13 |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
| 2 | Test User 02 | test02#domain.com | 0 | 3 | 0 |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
| 3 | Test User 03 | test03#domain.com | 0 | 3 | 0 |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
| 4 | Test User 04 | test04#domain.com | 0 | 3 | 0 |
+---------+--------------+-------------------+------------------------+------------------------+--------------------+
This is my query, but right answer result returns all of exams. I want get only sum of max right answer total for each courses.
Please also consider these cases:
A course can have more than one exams.
A user can join more than one course_exam.
SELECT DISTINCT
`user`.user_id,
(
SELECT COUNT(DISTINCT(`user_course_exam`.`course_exam_id`)) FROM `user_course_exam`
INNER JOIN `course_exam` ON (`course_exam`.`course_exam_id` = `user_course_exam`.`course_exam_id`)
WHERE `user_course_exam`.`user_id` = `user`.`user_id` && `course_exam`.course_id IN (
SELECT course_id FROM course_exam
WHERE status = '1'
GROUP BY `course_exam`.`course_id`
)
) AS completed_course,
(
SELECT SUM(`user_course_exam`.`right_answer_total`) FROM `user_course_exam`
INNER JOIN `course_exam` ON (`course_exam`.`course_exam_id` = `user_course_exam`.`course_exam_id`)
WHERE `user_course_exam`.`user_id` = `user`.`user_id` && `course_exam`.course_id IN (
SELECT course_id FROM course_exam
WHERE status = '1'
GROUP BY `course_exam`.`course_id`
) ORDER BY `user_course_exam`.`right_answer_total` DESC
) AS right_answer
FROM
`user`
WHERE
`user`.`user_id` > 0
GROUP BY
`user`.`user_id`
ORDER BY
`user`.`user_id` ASC
LIMIT 15 OFFSET 0
JSFiddle: http://sqlfiddle.com/#!9/72ee15/1/0
You can try to use MAX() than SUM()
SELECT DISTINCT `user`.`user_id`,
(
SELECT COUNT(DISTINCT (`user_course_exam`.`course_exam_id`))
FROM `user_course_exam`
INNER JOIN `course_exam`
ON (`course_exam`.`course_exam_id` = `user_course_exam`.`course_exam_id`)
WHERE `user_course_exam`.`user_id` = `user`.`user_id` && `course_exam`.`course_id` IN (
SELECT `course_id`
FROM `course_exam`
GROUP BY `course_exam`.`course_id`
)
) AS `completed_course`,
(
SELECT sum(`all_curse`.`max_right_answer`)
FROM (
SELECT MAX(`user_course_exam`.`right_answer_total`) AS `max_right_answer`,
`user_course_exam`.`user_id`
FROM `user_course_exam`
INNER JOIN `course_exam`
ON `course_exam`.`course_exam_id` = `user_course_exam`.`course_exam_id`
WHERE `course_exam`.`status` = 1
GROUP BY `course_exam`.`course_id`, `course_exam`.`course_exam_id`
) AS `all_curse`
WHERE `all_curse`.`user_id` = `user`.`user_id`
) AS `right_answer`
FROM `user`
WHERE `user`.`user_id` > 0
GROUP BY `user`.`user_id`
ORDER BY `user`.`user_id`
LIMIT 15 OFFSET 0
JSFiddle: Here

SQL, difficult fetching data query

Suppose I have such a table:
+-----+---------+-------+
| ID | TIME | DAY |
+-----+---------+-------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 1 |
| 1 | 1 | 2 |
| 2 | 2 | 2 |
| 3 | 3 | 2 |
| 1 | 1 | 3 |
| 2 | 2 | 3 |
| 3 | 3 | 3 |
| 1 | 1 | 4 |
| 2 | 2 | 4 |
| 3 | 3 | 4 |
| 1 | 1 | 5 |
| 2 | 2 | 5 |
| 3 | 3 | 5 |
+-----+---------+-------+
I want to fetch a table which represents 2 IDs which got the largest sum of TIME within the last 3 days (means from 3 to 5 in a DAY column)
So the correct result would be:
+-----+---------+
| ID | SUM |
+-----+---------+
| 3 | 9 |
| 2 | 6 |
+-----+---------+
The original table is much larger and more complex. So i need a generic approach.
Thanks in advance.
And so I just learned that MySQL used LIMIT instead of TOP...
fiddle
CREATE TABLE tbl (ID INT,tm INT,dy INT);
INSERT INTO tbl (id, tm, dy) VALUES
(1,1,1)
,(2,2,1)
,(3,3,1)
,(1,1,2)
,(1,1,1)
SELECT ID
,SUM(SumTimeForDay) SumTimeFromLastThreeDays
FROM (SELECT ID
,SUM(tm) SumTimeForDay
FROM tbl
GROUP BY ID, dy
HAVING dy > MAX(dy) -3) a
GROUP BY id
ORDER BY SUM(SumTimeForDay) DESC
LIMIT 2
select t1.`id`, sum(t1.`time`) as `sum`
from `table` t1
inner join ( select distinct `day` from `table` order by `day` desc limit 3 ) t2
on t2.`da`y = t1.`day`
group by t1.`id`
order by sum(t1.`time`) desc
limit 2

SQL sorting with multiple criteria

I have two tables.
Tab1:
+------------+
| id | title |
+------------+
| 1 | B |
| 2 | C |
| 3 | A |
| 4 | A |
| 5 | A |
| 6 | A |
| ... |
+------------+
Tab2:
+-------------------------------------------+
| id | item_id | item_key | item_value |
+-------------------------------------------+
| 1 | 1 | value | $4 |
| 2 | 1 | url | http://h.com/ |
| 3 | 2 | value | $5 |
| 4 | 3 | url | http://i.com/ |
| 5 | 3 | value | $1 |
| 6 | 3 | url | http://y.com/ |
| 7 | 4 | value | $2 |
| 8 | 4 | url | http://z.com/ |
| 9 | 5 | value | $1 |
| 10 | 5 | url | http://123.com/ |
| ... |
+-------------------------------------------+
item_id is a foreign key from tab1.
How do I make it so I get a table of ids from Tab1 in order according to criteria from both tables. The criteria are the following:
Order ASC by title. If title is the same,
Order DESC by value. If both title and value is the same,
Prioritize items who's 'url' key contains '123.com'.
The resulting table with the ordered results would be:
+------------+
| id | title |
+------------+
| 4 | A |
| 5 | A |
| 3 | A |
| 6 | A |
| 1 | B |
| 2 | C |
| ... |
+------------+
The results should include items that don't have the one, both, or none of the fields from Tab2 set.
As far as I understand, a simple join will do it. You'll have to join Tab2 twice, since you want to order by values from both rows.
SELECT Tab1.id, Tab1.title
FROM Tab1
JOIN Tab2 t2_val ON t2_val.item_id = Tab1.id AND t2_val.item_key='value'
JOIN Tab2 t2_url ON t2_url.item_id = Tab1.id AND t2_url.item_key='url'
ORDER BY title,
t2_val.item_value DESC,
t2_url.item_value LIKE '%123.com%' DESC
An SQLfiddle to test with.
A little complicated, because when you do the join you will get multiple rows. Here is an approach that aggregates tab2 before doing the join:
select t1.*
from Tab1 t1 left outer join
(select id,
max(case when item_key = 'value' then item_value end) as value,
max(case when item_key = 'url' then item_value end) as url
from Tab2 t2
group by id
) t2
on t1.id = t2.id
order by t1.title, t2.value desc,
(t2.url like '%123.com%') desc;

Counting from another table [mysql]

I have one table like this:
+----+---------+-------------+
| id | site_id | search_term |
+----+---------+-------------+
| 1 | 2 | apple |
| 2 | 2 | banana |
| 3 | 3 | cheese |
| 4 | 1 | aubergine |
+----+---------+-------------+
And another like this:
+----+---------+-------------+
| id | site_id | search_term |
+----+---------+-------------+
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 1 |
| 5 | 3 | 3 |
| 6 | 1 | 4 |
+----+---------+-------------+
I want to find out how many times each search_term shows up in the 2nd table, and how many times.
In other words, from this data, if I was asking about site_id 2, I'd want this to be returned:
+-------------+-------+
| search_term | count |
+-------------+-------+
| apple | 3 |
| banana | 1 |
+-------------+-------+
I'm familiar with basic joins and such, as well as COUNT, but I'm not sure how to count things from another table.
Thanks!
You could join the tables together, and count the number of rows in the second table:
select t1.search_term
, count(t2.id)
from table1 t1
left join table2 t2
on t1.id = t2.search_term
group by t1.search_term
Give this a try:
select t1.search_term, count(*) from t1
join t2 on t1.id = t2.search_term and t1.site_id = t2.site_id
where t1.site_id = 2
group by t1.search_term