Avoid using a subquery in a table join - mysql

In a MySQL 5.7 database, I have the following User table:
Name
Id
David
1
Frank
2
And the following Order table:
Id
Price
UserId
1
55
1
2
68
1
3
50
1
4
10
2
For every user, I want to select the price of the order with the biggest ID.
I can use the following query which adds additional complexity due to the nested subquery :
SELECT
User.Name,
last_user_order.Price
FROM User
LEFT JOIN (
SELECT Price, UserId FROM Order
ORDER BY Id DESC LIMIT 1
) AS last_user_order ON last_user_order.UserId = User.Id
There exist many questions here where the column to be selected is the same than the one being ordered. Hence, it is possible to use MAX in the first SELECT statement to avoid a subquery. Is it possible to avoid a subquery in my case?

For every user, I want to select the price of the order with the biggest ID.
That looks like:
SELECT
u.*,
o.Price,
FROM
User u
INNER JOIN Order o ON u.ID = o.UserID
INNER JOIN
(
SELECT MAX(ID) as OrderID FROM Order GROUP BY UserId
) maxO ON o.Id = maxO.OrderId

SELECT User.Name,
( SELECT Order.Price
FROM Order
WHERE Order.UserId = User.Id
ORDER BY Order.Id DESC LIMIT 1 ) LastPrice
FROM User;

Related

Select ID of a row with max value

How can I select the ID of a row with the max value of another column in a query that joins multiple tables?
For example, say I have three tables. tblAccount which stores a grouping of users, like a family. tblUser which stores the users, each tied to a record from tblAccount. And each user can be part of a plan, stored in tblPlans. Each plan has a Rank column that determines it's sorting when comparing the levels of plans. For example, Lite is lower than Premium. So the idea is that each user can have a separate plan, like Premium, Basic, Lite etc..., but the parent account does not have a plan.
How can I determine the highest plan in the account with a single query?
tblAccount
PKID
Name
1
Adams Family
2
Cool Family
tblUsers
PKID
Name
AccountID
PlanID
1
Bob
1
3
2
Phil
2
2
3
Suzie
2
1
tblPlans
PKID
Name
Rank
1
Premium
3
2
Basic
2
3
Elite
4
4
Lite
1
Here's the result I'm hoping to produce:
AccountID
Name
HighestPlanID
PlanName
2
Adams Family
1
Premium
I've tried:
SELECT U.AccountID, A.Name, MAX(P.Rank) AS Rank, P.PKID as HighestPlanID, P.Name as PlanName
FROM tblPlans P
INNER JOIN tblUsers U ON U.PlanID = P.PKID
INNER JOIN tblAccounts A ON U.AccountID = A.PKID
WHERE U.AccountID = 2
and the query will not always work, selecting the MAX of Rank does not select entire row's values from tblPlans.
I am looking for a solution that is compatible with mysql-5.6.10
You can join the tables and use ROW_NUMBER() to identify the row you want. Then filtering is ieasy.
For example:
select *
from (
select a.*, p.*,
row_number() over(partition by a.pkid order by p.rank desc) as rn
from tblaccount a
join tblusers u on u.accountid = a.pkid
join tblplans p on p.pkid = u.planid
) x
where rn = 1
Inside the subquery you can add where u.accountid = 2 to retrieve a single account of interest, instead of all of them.
With the help of #the-impaler, I massaged their answer a bit and came out with something very similar:
select *
from (
select a.*, p.*
from tblaccount a
join tblusers u on u.accountid = a.pkid
join tblplans p on p.pkid = u.planid
where u.accountid = 2
order by p.rank desc
) x limit 1
The subquery sorts each user by plan rank from top to bottom, and then the top level query selects the top most row with limit 1. It seems to work!

SQL select from two tables (user have max car)

I have two tables.
USER: ID | NAME_USER
CAR: ID | ID_USER | NAME_CAR
I want print user which have max car, how can i do this?
My try (not working):
SELECT `NAME_USER`, NAME_CARFROM FROM USER, CAR
Thank you for your help
Should be this
select user.name_user
from user
inner join (select id_user, count(*) num
from car group by id_user order by num desc limit 1) as t on t.id_user = user.id
Join the tables, count the number of cars per user, and show the one with the highest number.
SELECT name_user
FROM user
JOIN car
GROUP BY id_user
ORDER BY COUNT(*) DESC
LIMIT 1
If multiple users have the same max number of cars, this will pick one of them arbitrarily.

Joining two tables based upon the highest COUNT(*) from table2?

Okay, so I have two tables that I need to link together with a JOIN query. There is a table called likes and a table called users. The users table looks something like this
id name
----- ------
1 Mark
2 Mike
3 Paul
4 Dave
5 Chris
6 John
The likes table looks like this.
user_one user_two match_id
----- ------ --------
1 2 abc
2 1
1 3 acc
3 1 abb
1 5 aee
5 1
The expected result should be
id name
----- ------
1 Mark
The two tables should only be linked on the rows in the likes table where the users_one column is set to the value that is most commonly found in that column. In this case, the user with the id of 1 is in the likes table with the user_one column 3 times where the match_id isn't empty.
I've thought it out to be written something like this
SELECT users.*, likes.COUNT(*) AS count
FROM users
JOIN likes
ON users.id = likes.user_one
WHERE likes.match_id != ''
But, I know this isn't correct. Is there a way to link two tables with a JOIN only on the most common rows in one of the tables?
Would Grouping work for what you need... ?
SELECT users.id, users.name, count(*) AS count
FROM users
JOIN likes
ON users.id = likes.user_one
WHERE likes.match_id != ''
group by users.id, users.name
should give you something like
1 Mark 3
Should be something like this, if I understood the question
select top 1 user_one, name
from likes
inner join users ON users.id = likes.user_one
where match_id != ''
group by user_one
order by count(*) Desc
Are you looking for something like this?
select u.id, u.name, count(*)
from users u
inner join likes l
on l.id = l.user_one and l.match_id != ''
group by u.id, u.name
order by count(*) desc
limit 1
The limit 1, combined with sorting by the # of likes in descending order will result in getting one user - the one with the most matched likes.
Try:
select *
from users
where id in (
select id
from likes
group by id
order by count(*) desc, id
limit 1
)
The subquery returns the id of the row with the most appearances in the likes table (group by id and order by count(*) desc). I've added id to the order by to give predictable results in case there are multiple with the same number of appearances. This is used to join to the users table to give the resultset required.

sql join query to get most viewed atricles by country

having a hard time pulling articles based on user country views
i have the following tables with their fields
user: id, country_id
article: id
article_views: id, user_id, article_id
each time a user views an article I insert it into the article_views table, like this:
article_views.id article_id user_id
2 1 1
3 2 1
4 2 2
5 2 2
I want to pull the highest viewed article for current user.country_id. I imagine it will contain:
order by article_views.article_id DESC
Any suggestions?
This should work fine:
select article_id, count(*) as views
from article_views inner join user on article_views.user_id = user.id
group by user.country_id
order by views desc;
Edit. I forgot about grouping article_id as #Josien pointed, the correct query is:
select country_id, article_id, count(*) as views
from article_views inner join user on article_views.user_id = user.id
where country_id = ':countryID'
group by user.country_id, article_id
order by views desc;
select av.id, count(*) as views
from article_views av inner join user u on av.user_id = u.id
where u.country_id = 'cc'
group by u.country_id
order by views desc;

mysql left join selecting only highest from left table

I've tried adapting solutions from SELECT biggest row from a LEFT JOIN and mysql: How to INNER JOIN a table but limit join to 1 result with the highest vote or count? but can't figure it out.
I'm joining two tables, the one being joined has two duplicate rows, the only difference is field 'page_id' - I want the one with the highest page_id number
tagID page_id companyID teamID companyID
1510 289 16 9 16
1418 163 16 9 16
(there are other text fields I want but these aren't used in matching so excluded them here)
My original query was
SELECT * FROM `cms_company_tags`
LEFT JOIN `cms_companies` ON `cms_companies`.`companyID`=`cms_company_tags`.`companyID`
WHERE `cms_company_tags`.`teamID`='9'
ORDER BY `cms_companies`.`companyName` ASC
which selected both rows
tagID page_id companyID teamID newsID companyID
1510 289 16 9 0 16
1418 163 16 9 0 16
I've tried
Select cms_company_tags.*, cms_companies.*
From cms_company_tags
Left Join cms_companies
On cms_companies.companyID = cms_company_tags.companyID
And cms_companies.page_id = (
Select Max( t.page_id )
From cms_companies As t
Where t.page_id = cms_company_tags.page_id
GROUP BY cms_company_tags.tagID
ORDER BY cms_company_tags.tagID DESC
)
WHERE `cms_company_tags`.`teamID`='9'
ORDER BY `cms_companies`.`companyName` ASC
and
SELECT * FROM `cms_company_tags`
LEFT JOIN `cms_companies` ON `cms_companies`.`companyID`=`cms_company_tags`.`companyID`
AND `cms_companies`.`page_id` = (SELECT MAX(page_id) AS pageID from `cms_companies` where `cms_companies`.`page_id` = `cms_company_tags`.`page_id`)
WHERE `cms_company_tags`.`teamID`='9'
ORDER BY `cms_companies`.`companyName` ASC
Both of which return
tagID page_id companyID teamID newsID companyID
1510 289 16 9 0 NULL
1418 163 16 9 0 16
With all the text fields being NULL too
I want the only the highest page_id. I could live with a duplicate row with NULL for the text field if it were the highest one and not the lowest one as I'm getting how.
EDIT:
Although this solution from returns the LOWEST page_id it does filter out the duplicate, luckily for me the text parts I need weren't affected. Posting here in the hope this partial solution is useful to someone
SELECT *
FROM cms_company_tags
INNER JOIN (
SELECT companyID, companyName, page_path, MAX(page_id) AS MaxPageID
FROM cms_companies
GROUP BY cms_companies.page_id
) MaxPages ON
cms_company_tags.companyID = MaxPages.companyID AND
cms_company_tags.page_id = MaxPages.MaxPageID AND
cms_company_tags.teamID = 9
ORDER BY MaxPages.companyName ASC
First off: why are you joining? You're only selecting from the left table, so left joining to another table won't affect the results. An inner join would affect results (by omitting companies that don't exist in cms_companies), but a left join won't.
At any rate, to get the highest page ID by company ID and team ID, try this:
SELECT companyID, teamID, MAX(page_ID)
FROM cms_company_tags
GROUP BY companyID, teamID
Then to get the unique rows from cms_company_tags, just join to the "highest by ID" as a subquery:
SELECT tagID, page_id, companyID, teamID
FROM cms_company_tags
INNER JOIN (
SELECT companyID, teamID, MAX(page_ID) AS MaxPageID
FROM cms_company_tags
GROUP BY companyID, teamID
) MaxPages ON
cms_company_tags.companyID = MaxPages.companyID AND
cms_company_tags.teamID = MaxPages.teamID
cms_company_tags.page_id = MaxPages.MaxPageID
This query returns the max page and other information for all companies/teams. You can add WHERE teamID = 9 to limit results to team 9.
Have you used ROW_NUMBER windowed function in sql server.
May be what you are looking is this:
select * from(
select *,row_number()over(partition by companyid, teamid, newsid, companyid order by page_id desc) as num
from 'cms_company_tags'
left join 'cms_companies' on 'cms_companies'.'companyID'='cms_company_tags'.'companyID'
where 'cms_company_tags'.'teamID'='9'
)tbl
where tbl.num =1