Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LEFT JOIN order and limit

This is my query:

SELECT `p`.`name` AS 'postauthor', `a`.`name` AS 'authorname',
       `fr`.`pid`, `fp`.`post_topic` AS 'threadname', `fr`.`reason`
  FROM `z_forum_reports` `fr`
  LEFT JOIN `forums` `f` ON (`f`.`id` = `fr`.`pid`)
  LEFT JOIN `forums` `fp` ON (`f`.`first_post` = `fp`.`id`) 
  LEFT JOIN `ps` `p` ON (`p`.`id` = `f`.`author_guid`)
  LEFT JOIN `ps` `a` ON (`a`.`account_id` = `fr`.`author`)

My problem is this left join:

SELECT `a`.`name`, `a`.`level`
[..]
LEFT JOIN `ps` `a` ON (`a`.`account_id` = `fr`.`author`)

Since, in case a has MANY rows and it'll return like in my case:

NAME  | LEVEL
Test1 | 1
Test2 | 120
Test3 | 2
Test4 | 1 

I want it to select a.name with order of level desc and limit 1, so it'll return the name of higher level where (a.account_id = fr.author).

Hope you got me. If not, feel free to post a comment.

like image 417
Cyclone Avatar asked Oct 17 '11 00:10

Cyclone


People also ask

What does (+) mean in SQL joins?

The plus sign is Oracle syntax for an outer join. There isn't a minus operator for joins. An outer join means return all rows from one table. Also return the rows from the outer joined where there's a match on the join key.

Does the order of tables Matter in left join?

1 Answer. The order doesn't matter for INNER joins. As long as you change your selects from SELECT * to SELECT a.

Does number of rows increase after left join?

Left joins can increase the number of rows in the left table if there are multiple matches in the right table.

What is the format for a left join?

The LEFT JOIN keyword returns all records from the left table (table1), and the matching records from the right table (table2). The result is 0 records from the right side, if there is no match.


2 Answers

Try replacing:

LEFT JOIN ps a ON a.account_id = fr.author

with:

LEFT JOIN ps a 
  ON a.PrimaryKey                         --- the Primary Key of ps
     = ( SELECT b.PrimaryKey 
         FROM ps AS b 
         WHERE b.account_id = fr.author
         ORDER BY b.level DESC
         LIMIT 1
       )
like image 81
ypercubeᵀᴹ Avatar answered Oct 12 '22 09:10

ypercubeᵀᴹ


Replace the LEFT JOIN clause with something like:

...
LEFT JOIN (SELECT b.account_id, b.name
             FROM (SELECT c.account_id, MAX(c.level) AS level
                     FROM ps AS c
                    GROUP BY c.account_id) AS d
             JOIN ps AS b ON b.account_id = d.account_id AND b.level = d.level
          ) AS a
       ON (a.account_id = fr.author)
...

This will still return multiple rows if there were several rows in ps with the same account ID and the same level and that level was the maximum level:

NAME  | LEVEL
Test1 | 1
Test2 | 120
Test3 | 2
Test4 | 1
Test5 | 120

If this situation can arise, then you have to decide what you want to do - and tune the query appropriately. For example, you might decide to use MAX(b.name) with a GROUP BY clause to arbitrarily select the alphabetically later of the two names.

like image 31
Jonathan Leffler Avatar answered Oct 12 '22 09:10

Jonathan Leffler