mysql: how to save ORDER BY after LEFT JOIN without reorder?

前端 未结 4 861
你的背包
你的背包 2021-01-22 22:22

I\'ve two table:

1) profiles

+----+---------+
| id | name    |
+----+---------+
|  1 | WILLIAM |
|  2 | JOHN    |
|  3 | ROBERT  |
|  4 | MI         


        
相关标签:
4条回答
  • 2021-01-22 22:58

    (Explaining the loss of ORDER BY)

    The SQL standard essentially says that a subquery is an unordered set of rows. This implies that the Optimizer is free to ignore the ORDER BY in the 'derived' table: FROM ( SELECT ... ORDER BY ). In "recent" versions of MySQL and MariaDB, such ORDER BYs are being dropped. There are other cases where ORDER BY is ignored.

    In some situations (not sure about this one), adding a LIMIT 99999999 (big number) after the ORDER BY tricks the Optimizer into doing the ORDER BY. However, it is still free to ignore the "order" later.

    A general rule for MySQL: Avoid subqueries. (There are cases where subqueries are faster, but not yours.)

    A strong rule: You must have an ORDER BY on the outermost if you want the results to be sorted.

    If you had added LIMIT 3 to the derived table in your first query, you would get only CHARLES, DAVID, JAMES, but not necessarily in that order. That is, you would need two ORDER BYs - one in the derived table, one at the very end.

    0 讨论(0)
  • 2021-01-22 22:58
    SELECT * 
      FROM profiles p 
      LEFT 
      JOIN request_for_friendship r 
        ON (r.from_id = p.id AND r.to_id = 1) 
        OR (r.from_id = 1 AND r.to_id = p.id)  
     ORDER 
        BY name;
    +----+---------+------+---------+-------+
    | id | name    | id   | from_id | to_id |
    +----+---------+------+---------+-------+
    |  8 | CHARLES |    3 |       1 |     8 |
    |  6 | DAVID   | NULL |    NULL |  NULL |
    |  5 | JAMES   | NULL |    NULL |  NULL |
    |  2 | JOHN    |    1 |       1 |     2 |
    |  9 | JOSEPH  |    6 |       9 |     1 |
    |  4 | MICHAEL |    5 |       4 |     1 |
    |  7 | RICHARD | NULL |    NULL |  NULL |
    |  3 | ROBERT  |    2 |       1 |     3 |
    | 10 | THOMAS  | NULL |    NULL |  NULL |
    |  1 | WILLIAM | NULL |    NULL |  NULL |
    +----+---------+------+---------+-------+
    10 rows in set (0.02 sec)
    
    mysql>
    
    0 讨论(0)
  • 2021-01-22 22:59

    I know this question is a couple of years old, but I didn't find this possible solution already offered. This is the solution that worked best for me to keep the subquery results in the correct order.

    Consider adding a "row_number" to your subquery. Then use ORDER BY on row_number.

    This explains how to add the row_number: select increment counter in mysql

    In my case, I have an unknown number of possible rows in a hierarchical recursive query that I need to keep the order results of the subquery to remain the same in the outer query.

    This is my query:

    SELECT l.row_number, l.userid, l.child, p.id, p.username
    FROM (
    
        SELECT  @rownum := @rownum + 1 AS row_number, u.parent AS userid, _id  AS child 
                    FROM (
                        SELECT  @r AS _id, (SELECT  @r := parent FROM new_clean WHERE userid = _id) AS parent
                                    FROM (SELECT @r := ?) AS vars, new_clean h
                                    WHERE   @r <> 0 
                        ) u
                    CROSS JOIN (SELECT @rownum := 0) r
                    WHERE u.parent <> 0                     
        ) l 
    
            LEFT JOIN profile p ON p.userid = l.userid
            ORDER BY row_number
    
    0 讨论(0)
  • 2021-01-22 23:10

    Try this:

    SELECT
        a.name as `from_name`,
        b.name as `to_name`,
        c.from_id,
        c.to_id
    FROM profiles a
    LEFT JOIN request_for_friendship c
    ON a.id = c.from_id
    LEFT JOIN profiles b
    ON c.to_id = b.id
    GROUP BY a.name,b.name
    ORDER BY a.name,b.name;
    

    Or, if you want one row per "from" name:

    SELECT
        a.name as `from_name`,
        IFNULL(GROUP_CONCAT(b.name),'-none-') as `to_name`,
        IFNULL(c.from_id,'-none-') as `from_id`,
        IFNULL(GROUP_CONCAT(c.to_id),'-none-') as `to_id`
    FROM profiles a
    LEFT JOIN request_for_friendship c
    ON a.id = c.from_id
    LEFT JOIN profiles b
    ON c.to_id = b.id
    GROUP BY a.name
    ORDER BY a.name,b.name
    
    0 讨论(0)
提交回复
热议问题