mysql:如何在LEFT JOIN之后保存ORDER BY而不重新排序?

时间:2017-04-28 10:52:45

标签: mysql sql join left-join sql-order-by

我有两张桌子:

1)profiles

+----+---------+
| id | name    |
+----+---------+
|  1 | WILLIAM |
|  2 | JOHN    |
|  3 | ROBERT  |
|  4 | MICHAEL |
|  5 | JAMES   |
|  6 | DAVID   |
|  7 | RICHARD |
|  8 | CHARLES |
|  9 | JOSEPH  |
| 10 | THOMAS  |
+----+---------+

2)request_for_friendship

+----+---------+-------+
| id | from_id | to_id |
+----+---------+-------+
|  1 |       1 |     2 |
|  2 |       1 |     3 |
|  3 |       1 |     8 |
|  5 |       4 |     1 |
|  6 |       9 |     1 |
+----+---------+-------+

我需要对所有profiles进行一些排序,然后将其加入request_for_friendship

例如,让所有用户进行一些排序:

mysql>     SELECT *
    ->     FROM  profiles
    ->     ORDER BY name ASC;
+----+---------+
| id | name    |
+----+---------+
|  8 | CHARLES |
|  6 | DAVID   |
|  5 | JAMES   |
|  2 | JOHN    |
|  9 | JOSEPH  |
|  4 | MICHAEL |
|  7 | RICHARD |
|  3 | ROBERT  |
| 10 | THOMAS  |
|  1 | WILLIAM | <-- WILLIAM IS LAST!
+----+---------+

一切看起来都很好,排序存在。之后我加入了request_for_friendship,我的sotring将会休息:

mysql> SELECT * FROM
    -> (
    ->     SELECT *
    ->     FROM  profiles
    ->     ORDER BY name ASC
    -> ) as users
    ->     LEFT JOIN request_for_friendship
    ->     AS request_for_friendship_copy
    ->     ON
    ->     (
    ->         request_for_friendship_copy.from_id = 1
    ->         AND
    ->         request_for_friendship_copy.to_id = users.id
    ->     )
    ->     OR
    ->     (
    ->         request_for_friendship_copy.from_id = users.id
    ->         AND
    ->         request_for_friendship_copy.to_id = 1
    ->     );
+----+---------+------+---------+-------+
| id | name    | id   | from_id | to_id |
+----+---------+------+---------+-------+
|  2 | JOHN    |    1 |       1 |     2 |
|  3 | ROBERT  |    2 |       1 |     3 |
|  8 | CHARLES |    3 |       1 |     8 |
|  4 | MICHAEL |    5 |       4 |     1 |
|  9 | JOSEPH  |    6 |       9 |     1 |
|  1 | WILLIAM | NULL |    NULL |  NULL | <-- WILLIAM IN THE MIDDLE!
|  5 | JAMES   | NULL |    NULL |  NULL |
|  6 | DAVID   | NULL |    NULL |  NULL |
|  7 | RICHARD | NULL |    NULL |  NULL |
| 10 | THOMAS  | NULL |    NULL |  NULL |
+----+---------+------+---------+-------+

如何JOIN LEFT 原始排序保存?

我无法对 JOIN LEFT之后的结果进行排序,因为ORDER BY JOIN在我的数据库中需要~0.02s (约1 000 000位用户)但是当ORDER BY JOIN //Revrse an array import java.util.*; public class ReverseSecond { static int revArray(int []d) { int temp=0; for(int i=0;i<d.length/2;i++) { temp=d[i]; d[i]=d[d.length-1-i]; d[d.length-1-i]=temp; } return d; } public static void main(String h[]) { int no[]={10,20,30,40,50}; System.out.println("Before Reverse:-"); for(int i=0;i<no.length;i++) { System.out.println(""+no[i]); } System.out.println("Reverse Array is :-"+revArray(no)); } } 后需要大约3.2秒时,这是非常大的时间:(

Demo: rextester.com/DLLM29415

Demo: http://sqlfiddle.com/#!9/167792/1

以sqlfiddle顺序保存!但是怎么样? MySQL 5.6保存了订单?

4 个答案:

答案 0 :(得分:2)

(解释失去ORDER BY

SQL标准基本上说子查询是一组无序的行。这意味着优化工具可以自由地忽略“派生”表中的ORDER BYFROM ( SELECT ... ORDER BY )。在MySQL和MariaDB的“最新”版本中,正在删除此类ORDER BYs。在其他情况下,忽略ORDER BY

某些情况下(不确定此情况),在LIMIT 99999999诱骗优化程序执行ORDER BY之后添加ORDER BY(大号) 。但是,它仍然可以在以后忽略“订单”。

MySQL的一般规则:避免使用子查询。 (有些情况下子查询更快,但不是你的。)

强有力的规则:如果您希望对结果进行排序,那么必须在最外面有ORDER BY

如果您在第一个查询中将LIMIT 3添加到派生表中,则只能获得CHARLES,DAVID,JAMES,,但不一定按此顺序。也就是说,你需要两个ORDER BYs - 派生表中的一个,最后一个。

答案 1 :(得分:0)

试试这个:

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

或者,如果你想要每行#34;来自&#34;名:

this

答案 2 :(得分:0)

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>

答案 3 :(得分:0)

我知道这个问题已经有两年了,但是我没有找到这个可能的解决方案。对于我来说,这是使子查询结果保持正确顺序最有效的解决方案。

请考虑在您的子查询中添加“行号”。然后在row_number上使用ORDER BY。

这说明了如何添加row_number: select increment counter in mysql

就我而言,在层次结构递归查询中可能存在的行数未知,我需要保持子查询的顺序结果在外部查询中保持不变。

这是我的查询

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