Select the highest record of each relation - mysql

I need to get the most visited site of all users
I have the following tables:
page:
id link_page
1 link 1
2 link 2
3 Link 3
user:
id name
1 Joseph
2 Cris
3 Byram
pages_user:
user_id page_id
1 1
1 1
1 1
2 1
2 1
2 2
Should obtain the following:
user_id | most visited page id
1 1
2 1
So far I did something like this:
SELECT count(pu.page_id) as counter, pu.user_id
FROM page_user pu
INNER JOIN page p on p.id = pu.page_id
INNER JOIN users u on u.id = pu.user_id
GROUP BY pu.user_id, pu.page_id
ORDER BY counter DESC
But I return all the records.
As I can get the site most visited of all users?
Greetings from Chile.

You can try this:
SELECT
t.user_id,
t.page_id AS most_visited_page_id
FROM (
SELECT
pu.user_id,
pu.page_id,
COUNT(*) AS visitCount
FROM page_user pu
INNER JOIN page p ON p.id = pu.page_id
INNER JOIN user u ON u.id = pu.user_id
GROUP BY pu.user_id, pu.page_id
ORDER BY pu.user_id, visitCount DESC, rand() <-- In case of multiple
page with same count it will give random page or you can check
it with most recent visit with date if any -->
) AS t
GROUP BY t.user_id
Here is the sqlfiddle.

SELECT id, (SELECT page_id FROM page_user
WHERE user_id = id GROUP BY page_id
ORDER BY COUNT(page_id) DESC LIMIT 1) FROM USER
Try this query . You may modify to show all required fields
EDIT : To see the number of hits, use the following query.
SELECT id, (SELECT page_id FROM page_user
WHERE user_id = id GROUP BY page_id
ORDER BY COUNT(page_id) DESC LIMIT 1) page_id, (SELECT COUNT(page_id) cnt FROM page_user
WHERE user_id = id GROUP BY page_id
ORDER BY cnt DESC LIMIT 1) cnt FROM USER

Here is a way of doing it, consider the following
mysql> select * from user;
+------+--------+
| id | name |
+------+--------+
| 1 | Joseph |
| 2 | Cris |
| 3 | Byam |
+------+--------+
3 rows in set (0.00 sec)
mysql> select * from page;
+------+-----------+
| id | link_page |
+------+-----------+
| 1 | link 1 |
| 2 | link 2 |
| 3 | link 3 |
+------+-----------+
3 rows in set (0.00 sec)
+---------+---------+
| user_id | page_id |
+---------+---------+
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 2 | 1 |
| 2 | 1 |
| 2 | 2 |
| 3 | 2 |
| 3 | 2 |
| 3 | 2 |
| 3 | 1 |
| 3 | 3 |
| 3 | 3 |
+---------+---------+
12 rows in set (0.00 sec)
select
u.id as user_id,
p.id as `most visited page id`
from user u join (
select count(*) as cnt,user_id,page_id from pages_user group by user_id,page_id
)x on x.user_id = u.id
left join(
select count(*) as cnt,user_id,page_id from pages_user group by user_id,page_id
)y on x.user_id = y.user_id and y.cnt > x.cnt
join page p on p.id = x.page_id
where y.user_id is null ;
+---------+----------------------+
| user_id | most visited page id |
+---------+----------------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
+---------+----------------------+

Related

mysql LEFT JOIN main table and two additional tables with max value from each

So i have three tables:
Users
+-------+-----+----+
| id | val1|val2|
+-------+-----+----+
| 1 | 1 |3 |
| 2 | 2 |5 |
| 3 | 4 |7 |
+-------+-----+----+
UsersData
+----+--------------+------------+-----|
| id | users_id | created_at | gold|
+----+--------------+------------+-----|
| 9 | 1 |121454561212| 14 |
| 10| 1 |131454561212| 2 |
| 11| 2 |111454561212| 99 |
+----+--------------+------------+-----+
Extra
+----+------------+-----|
| id | users_id | val4|
+----+------------+-----|
| 1 | 1 | 5 |
| 2 | 1 | 6 |
| 3 | 1 | 7 |
+----+------------+-----+
So what i wish to achieve(in a single query) is to get a single row result for user with id = 1, that holds:
everything from Users Table
gold value of the most recent entry for that user (users_id = 1, created_at = MAX)
biggest val4 from the Extra table, where users_id = 1
So the result row would look like this:
+-------+-----+----+-----+----+
| id | val1|val2|gold |val4|
+-------+-----+----+-----+----|
| 1 | 1 |3 | 2 | 7 |
------------------------------+
I can get The first part done with
SELECT Users.id, Users.val1, Users.val2, UsersData.gold
FROM UsersData
LEFT JOIN Users ON UsersData.users_id = Users.id
WHERE Users.id = 1
ORDER BY UsersData.created_at DESC
LIMIT 1
and the second part with
SELECT MAX(Distances.distance) AS maxdistance FROM Distances WHERE Distances.users_id = 1
But i can't combine them no matter how i try... I would really like to have this done in single query, obviously i can do it with multiple - but i believe it is just my lack of mysql skills that is the issue here.
Thanks!
Just use subquery:
SELECT Users.id, Users.val1, Users.val2, UsersData.gold,
(SELECT MAX(Distances.distance) FROM Distances WHERE Distances.users_id = Users.id) AS maxdistance
FROM UsersData
RIGHT JOIN Users ON UsersData.users_id = Users.id
WHERE Users.id = 1
ORDER BY UsersData.created_at DESC
LIMIT 1
This is subquery connected by Users.id:
SELECT MAX(Distances.distance) FROM Distances WHERE Distances.users_id = Users.id) AS maxdistance
I would use subqueries like this:
select u.*,
(select ud.gold
from userdata ud
where ud.users_id = u.id
order by ud.created_at desc
limit 1
) as most_recent_gold,
(select max(e.val4)
from extra e
where e.users_id = u.id
) as max_val4
from users u
where u.id = 1 ;

Count distinct records from child table for each user in MYSQL

I have a competition which counts how many species each user has collected.
this is managed by 3 tables:
a parent table called "sub" with collection,each collection is unique, has an id and is associated to a user id.
+----+---------+
| id | user_id |
+----+---------+
| 1 | 1 |
| 2 | 10 |
| 3 | 1 |
| 4 | 3 |
| 5 | 1 |
| 6 | 10 |
+----+---------+
the child table called "sub_items" contains multiple unique records of the specs and is related to the parent table by the sub id to id.(each sub can have multiple records of specs)
+----+--------+---------+--+
| id | sub_id | spec_id | |
+----+--------+---------+--+
| 1 | 1 | 1000 | |
| 2 | 1 | 1003 | |
| 3 | 1 | 2520 | |
| 4 | 2 | 7600 | |
| 5 | 2 | 1000 | |
| 6 | 3 | 15 | |
+----+--------+---------+--+
a user table with associated user_id
+--------+-------+--+
| usename | name |
+---------+-------+--+
| 1 | David |
| 10 | Ruth |
| 3 | Rick |
+--------+-------+--+
i need to list the users with the most unique specs collected in a decsending order.
output expected:
David has a total of 2 unique specs.Ruth has a total of 2 unique specs.
+--------+---------+
| id | total |
+----+-------------+
| David | 2 |
| Ruth | 2 |
| Rick | 2 |
+----+-------------+
so far i have this,it produces a result. but its not accurate, it counts the total records.
im probably missing a DISTINCT somewhere in the sub-query.
SELECT s.id, s.user_id,u.name, sum(t.count) as total
FROM sub s
LEFT JOIN (
SELECT id, sub_id, count(id) as count FROM sub_items GROUP BY sub_id
) t ON t.sub_id = s.id
LEFT JOIN user u ON u.username = s.user_id
GROUP BY user_id
ORDER BY total DESC
i have looked at this solution, but it doesn't consider the unique aspect
You'll first have to get the max "score" for all the users like:
SELECT count(DISTINCT si.id) as total
FROM sub INNER JOIN sub_items si ON sub.id = su.sub_id
GROUP BY sub.user_id
ORDER BY total DESC
LIMIT 1
Then you can use that to restrict your query to users that share that max score:
SELECT u.name, count(DISTINCT si.id) as total
FROM
user u
INNER JOIN sub ON u.usename = sub.user_id
INNER JOIN sub_items si ON sub.id = su.sub_id
GROUP BY u.name
HAVING total =
(
SELECT count(DISTINCT si.id) as total
FROM sub INNER JOIN sub_items si ON sub.id = su.sub_id
GROUP BY sub.user_id
ORDER BY total DESC
LIMIT 1
)
this worked for me, i have to add the
COUNT(distinct spec_id)
to the sub-query
SELECT s.id, s.user_id,u.name, sum(t.count) as total
FROM sub s
LEFT JOIN (
SELECT sub_id, COUNT(distinct spec_id) as count FROM sub_items group by sub_id
) t ON t.sub_id = s.id
LEFT JOIN user u ON u.username = s.user_id
GROUP BY user_id
ORDER BY total DESC

Select two items with maximum number of common values

I have the following table:
+----+-----------+-----------+
| id | teacherId | studentId |
+----+-----------+-----------+
| 1 | 1 | 4 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
| 4 | 1 | 3 |
| 5 | 2 | 2 |
| 6 | 2 | 1 |
| 7 | 2 | 3 |
| 8 | 3 | 9 |
| 9 | 3 | 6 |
| 10 | 1 | 6 |
+----+-----------+-----------+
I need a query to find two teacherId's with maximum number of common studentId's.
In this case teachers with teacherIds 1,2 have common students with studentIds 2, 1, 3, which is greater than 1,3 having common students 6.
Thanks in Advance!
[Edit]: After several hours I've had the following solution:
SELECT * FROM (
SELECT r1tid, r2tid, COUNT(r2tid) AS cnt
FROM (
SELECT r1.teacherId AS r1tid, r2.teacherId AS r2tid
FROM table r1
INNER JOIN table r2 ON r1.studentId=r2.studentId AND r1.teacherId!=r2.teacherId
ORDER BY r1tid
) t
GROUP BY r1tid, r2tid
ORDER BY cnt DESC
) t GROUP BY cnt ORDER BY cnt DESC LIMIT 1;
I was sure that there must exist more short and elegant solution, but I could not find it.
You would do this with a self-join. Assuming no duplicates in the table:
select t.teacherid, t2.teacherid, count(*) as NumStudentsInCommon
from table t join
table t2
on t.studentid = t2.studentid and
t.teacherid < t2.teacherid
group by t.teacherid, t2.teacherid
order by NumStudentsInCommon desc
limit 1;
If you had duplicates, you would just replace count(*) with count(distinct studentid), but count(distinct) requires a bit more work.
select t.teacherId, t2.teacherId, sum(t.studentId) as NumStudentsInCommon
from table1 t join
table1 t2
on t.studentId = t2.studentId and
t.teacherId < t2.teacherId
group by t.teacherId, t2.teacherId
order by NumStudentsInCommon desc

Select row from one table where multiple rows in another table have determined values

I have two tables in MySQL:
Products:
id | value
================
1 | foo
2 | bar
3 | foobar
4 | barbar
And properties:
product_id | property_id
=============================
1 | 10
1 | 11
2 | 15
2 | 16
3 | 10
3 | 11
4 | 10
4 | 16
I want to get products that have determined properties.
For example I need to get all products that have properties with ids 10 and 11. And I expect products with ids 1 and 3 but not 4!
Is it possible in mysql or I need to use PHP for it?
Thank you!
with ids 10 and 11
Here's 2 solutions:
SELECT p.id,
p.value,
Count(DISTINCT propety_id)
FROM products p
INNER JOIN properties pr
ON p.id = pr.product_id
AND propety_id IN ( 10, 11 )
HAVING Count(DISTINCT propety_id) = 2;
or....
SELECT p.id,
p.value
FROM products p
INNER JOIN properties pr1
ON p.id = pr2.product_id
AND pr1.propety_id = 10
INNER JOIN properties pr2
ON p.id = pr2.product_id
AND pr2.propety_id = 11;
As for excluding rows - add a NOT exists clause, or do an additional left join and exclude matching rows.
SELECT *
FROM [products]
WHERE id IN (SELECT product_id
FROM [properties]
WHERE propety_id IN ( '10', '11' )
HAVING Count(DISTINCT propety_id) = 2);
Try this:
SELECT p.id
FROM product p
INNER JOIN properties prop
ON p.id = prop.product_id
AND property_id IN ( 10, 11 )
GROUP BY p.id
HAVING Count(DISTINCT property_id) = 2
Here is how I solved it:
mysql> SELECT * FROM products;
+----+--------+
| id | value |
+----+--------+
| 1 | foo |
| 2 | bar |
| 3 | foobar |
| 4 | barbar |
+----+--------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM properties;
+------------+-------------+
| product_id | property_id |
+------------+-------------+
| 1 | 10 |
| 1 | 11 |
| 2 | 15 |
| 2 | 16 |
| 3 | 10 |
| 3 | 11 |
| 4 | 10 |
| 4 | 16 |
+------------+-------------+
8 rows in set (0.00 sec)
Now we select all the product ids, that have property_ids IN (10, 11) and having 2 distinct rows for property_id:
mysql> SELECT
product_id FROM properties
WHERE
properties.property_id IN (10, 11)
GROUP BY
product_id
HAVING
COUNT(DISTINCT property_id) = 2;
+------------+
| product_id |
+------------+
| 1 |
| 3 |
+------------+
2 rows in set (0.01 sec)
Combining this query with SELECT-ing from products:
mysql> SELECT
id, value
FROM
products
WHERE
products.id IN(
SELECT
product_id FROM properties
WHERE
properties.property_id IN (10, 11)
GROUP BY
product_id
HAVING
COUNT(DISTINCT property_id) = 2);
+----+--------+
| id | value |
+----+--------+
| 1 | foo |
| 3 | foobar |
+----+--------+
2 rows in set (0.00 sec)
sql fiddle
Try this one
SELECT Prd.*
FROM products As Prd
LEFT JOIN (SELECT product_id ,SUM(RStatus) As Tt
FROM (SELECT product_id,
CASE
WHEN propety_id = 10 THEN NULL
WHEN propety_id = 11 THEN NULL
ELSE 0
END As RStatus
FROM properties
) A
GROUP BY product_id
) AS Prt ON(Prd.ID = Prt.product_id )
WHERE Prt.Tt IS NULL

Joining two tables without returning unwanted row

My table structure looks like this:
tbl.users tbl.issues
+--------+-----------+ +---------+------------+-----------+
| userid | real_name | | issueid | assignedid | creatorid |
+--------+-----------+ +---------+------------+-----------+
| 1 | test_1 | | 1 | 1 | 1 |
| 2 | test_2 | | 2 | 1 | 2 |
+--------+-----------+ +---------+------------+-----------+
Basically I want to write a query that will end in a results table looking like this:
(results table)
+---------+------------+---------------+-----------+--------------+
| issueid | assignedid | assigned_name | creatorid | creator_name |
+---------+------------+---------------+-----------+--------------+
| 1 | 1 | test_1 | 1 | test_1 |
| 2 | 1 | test_1 | 2 | test_2 |
+---------+------------+---------------+-----------+--------------+
My SQL looks like this at the moment:
SELECT
`issues`.`issueid`,
`issues`.`creatorid`,
`issues`.`assignedid`,
`users`.`real_name`
FROM `issues`
JOIN `users`
ON ( `users`.`userid` = `issues`.`creatorid` )
OR (`users`.`userid` = `issues`.`assignedid`)
ORDER BY `issueid` ASC
LIMIT 0 , 30
This returns something like this:
(results table)
+---------+------------+-----------+-----------+
| issueid | assignedid | creatorid | real_name |
+---------+------------+-----------+-----------+
| 1 | 1 | 1 | test_1 |
| 2 | 1 | 2 | test_1 |
| 2 | 1 | 2 | test_2 |
+---------+------------+-----------+-----------+
Can anyone help me get to the desired results table?
SELECT
IssueID,
AssignedID,
CreatorID,
AssignedUser.real_name AS AssignedName,
CreatorUser.real_name AS CreatorName
FROM Issues
LEFT JOIN Users AS AssignedUser
ON Issues.AssignedID = AssignedUser.UserID
LEFT JOIN Users AS CreatorUser
ON Issues.CreatorID = CreatorUser.UserID
ORDER BY `issueid` ASC
LIMIT 0, 30
On the general knowledge front, our illustrious site founder wrote a very nice blog article on this subject which I find myself referring to over and over again.
Visual Explanation of SQL Joins
Use this:
SELECT
`issues`.`issueid`,
`issues`.`creatorid`,
`creator`.`real_name`,
`issues`.`assignedid`,
`assigned`.`real_name`
FROM `issues` i
INNER JOIN `users` creator ON ( `creator`.`userid` = `issues`.`creatorid` )
INNER JOIN `users` assigned ON (`assigned`.`userid` = `issues`.`assignedid`)
ORDER BY `issueid` ASC
LIMIT 0 , 30
SELECT DISTINCT (i.issueid, i.creatorid, i.assignedid, u.real_name)
FROM issues i, users u
WHERE u.userid = i.creatorid OR u.userid = assignedid
ORDER BY i.issueid ASC
LIMIT 0 , 30
Not sure if the parenthesis are needed or not.
Does this work?
SELECT
i.issueid,
i.assignedid,
u1.real_name as assigned_name,
i.creatorid,
u2.real_name as creator_name
FROM users u1
INNER JOIN issues i ON u1.userid = i.assignedid
INNER JOIN users u2 ON u2.userid = i.creatorid
ORDER BY i.issueid
SELECT
i.issueid,
i.assignedid,
a.real_name,
i.creatorid,
c.real_name
FROM
issues i
INNER JOIN users c
ON c.userid = i.creatorid
INNER JOIN users a
ON a.userid = i.assignedid
ORDER BY
i.issueid ASC