MySQL group by with ordering/priority of another column

若如初见. 提交于 2019-12-05 10:47:53

You can use that MAX example, you just needed to "fake it". See here: http://sqlfiddle.com/#!2/58688/5

SELECT *
FROM test
JOIN (SELECT 'west' AS direction, 4 AS weight
      UNION
      SELECT 'north',3
      UNION
      SELECT 'south',2
      UNION
      SELECT 'east',1) AS priority
  ON priority.direction = test.direction
JOIN (
      SELECT route, MAX(weight) AS weight
      FROM test
      JOIN (SELECT 'west' AS direction, 4 AS weight
            UNION
            SELECT 'north',3
            UNION
            SELECT 'south',2
            UNION
            SELECT 'east',1) AS priority
        ON priority.direction = test.direction
      GROUP BY route
) AS t1
  ON t1.route = test.route
    AND t1.weight = priority.weight

I came up with this solution, however, it is ugly. Anyway, you may try it:

CREATE TABLE test (
  route INT,
  direction VARCHAR(20),
  operatorName VARCHAR(20)
);

INSERT INTO test VALUES(95, 'east', 'James');
INSERT INTO test VALUES(95, 'west', 'Richard');
INSERT INTO test VALUES(95, 'north', 'Dave');
INSERT INTO test VALUES(95, 'south', 'Devon');
INSERT INTO test VALUES(96, 'east', 'Mark');
INSERT INTO test VALUES(96, 'west', 'Andrew');
INSERT INTO test VALUES(96, 'south', 'Alex');
INSERT INTO test VALUES(96, 'north', 'Ryan');
INSERT INTO test VALUES(97, 'north', 'Justin');
INSERT INTO test VALUES(97, 'south', 'Tyler');

SELECT
    route,
    (SELECT operatorName
       FROM test
     WHERE route = t2.route
       AND direction =
              CASE
                WHEN direction_priority = 1 THEN 'west'
                WHEN direction_priority = 2 THEN 'north'
                WHEN direction_priority = 3 THEN 'south'
                WHEN direction_priority = 4 THEN 'east'
              END) AS operator_name
  FROM (
    SELECT
        route,
        MIN(direction_priority) AS direction_priority
      FROM (
        SELECT
            route,
            operatorName,
            CASE
              WHEN direction = 'west' THEN 1
              WHEN direction = 'north' THEN 2
              WHEN direction = 'south' THEN 3
              WHEN direction = 'east' THEN 4
            END AS direction_priority
          FROM test
      ) t
    GROUP BY route
  ) t2
;

Firstly, we select all records with direction changed to a number so it is in required order. Then, we GROUP by each route and get the minimal direction. What is left remains in the outermost query - select the operator name based on the lowest found direction.

Output:

ROUTE  OPERATOR_NAME
95  Richard
96  Andrew
97  Justin

Please, next time attach sample data not as a picture, but either as a plain text, or as inserts (best at SQLFiddle).

Check this solution at SQLFiddle

you can enumerate the directions using a case construct to make them sortable in your order. then rank the directions partitioned by route and then only select the first candidate.

set @c = 1;
set @r = '';

select route
     , direction
     , operatorName
  from (
         select route
              , direction
              , operatorName
              , @c := if (@r = route, @c + 1, 1) as cand
           from (
                  select route
                       , case when direction = 'west'
                              then 1
                              when direction = 'north'
                              then 2
                              when direction = 'south'
                              then 3
                              when direction = 'east'
                              then 4
                              else 5
                         end as enum_direction
                       , direction
                       , operatorName
                )
          order by
                route
              , enum_direction
       )
select *
from routes r1
where exists (
    select 1
    from routes r2
    where r1.route_id = r2.route_id
    group by r2.route_id
    having min(case r1.direction
                 when 'west' then 1
                 when 'north' then 2
                 when 'south' then 3
                 when 'east' then 4 end) = min(case r2.direction
                                                  when 'west' then 1
                                                  when 'north' then 2
                                                  when 'south' then 3
                                                  when 'east' then 4 end)
)

demo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!