MySQL分组依据,排序/优先级为另一列
我已经研究了这两个问题:MySQL分组依据,排序/优先级为另一列,mysql,sql,group-by,sql-order-by,Mysql,Sql,Group By,Sql Order By,我已经研究了这两个问题: 但是,它们都使用聚合函数MAX来获得最高值或填充值,这对我的情况不起作用 为了回答这个问题,我简化了我的情况。以下是我目前的数据: 我想获得每条路线的运营商名称,但与行驶方向有关(即订购或“首选”值)。这是我的伪代码: if(`direction` = 'west' AND `operatorName` != '') then select `operatorName` else if(`direction` = 'north' AND `operatorNa
if(`direction` = 'west' AND `operatorName` != '') then select `operatorName`
else if(`direction` = 'north' AND `operatorName` != '') then select `operatorName`
else if(`direction` = 'south' AND `operatorName` != '') then select `operatorName`
else if(`direction` = 'east' AND `operatorName` != '') then select `operatorName`
我当前的SQL查询是:
SELECT route, operatorName
FROM test
GROUP BY route
这为我提供了分组,但对于我而言,运算符是错误的:
route | operatorName
--------------------
95 | James
96 | Mark
97 | Justin
我曾尝试应用ORDER BY
子句,但GROUP BY
优先。我期望的结果是:
route | operatorName
--------------------
95 | Richard
96 | Andrew
97 | Justin
我不能在这里执行MAX()
,因为按字母顺序,“北”在“南”之前。在应用GROUP BY
子句之前,如何明确说明我的偏好/顺序
还要记住,空字符串不是首选
请注意,这是一个简化的示例。实际的查询选择了更多的字段并与其他三个表联接,但查询中没有聚合函数。您可以使用case构造枚举方向,使它们可以按顺序排序。然后对按路线划分的方向进行排序,然后只选择第一个候选方向
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
)
我想出了这个解决方案,然而,它是丑陋的。无论如何,你可以试试:
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
;
首先,我们选择方向
更改为数字的所有记录,使其符合要求的顺序。然后,我们对每条路线进行分组,得到最小方向。剩下的内容保留在最外面的查询中-根据找到的最低方向选择运算符名称
输出:
ROUTE OPERATOR_NAME
95 Richard
96 Andrew
97 Justin
路由操作员名称
95理查德
96安德鲁
97贾斯汀
请下次不要将样本数据作为图片,而是作为纯文本或插入内容(最好是)
请在处查看此解决方案。您可以使用MAX示例,您只需“伪造它”。请看这里:
没有聚合函数的GROUP BY是任意的。您想做什么(使用GROUP BY)毫无意义@Mihai对于不使用
GROUP BY
来获得我想要的结果的查询,我很乐意接受建议……在我看来,解决方案应该是将表本身和您在4种情况下输入的子查询进行内部联接,但我不确定我能做到。谢谢@Mihai,我已经使用变量而不是窗口函数修改了我的答案。我忘记了它们在mysql中是不可用的。唉,我不能完全肯定这会奏效。请随意编辑。
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
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)
)