假设我有两个表 a 和 b ; id 列在表 a 中是唯一的,但表 b 中有多个条目,列 x 的值不同以及该表中的其他列。表 b 的主键是(id,x)。
我需要能够将 b 中的单行连接到SELECT查询,就像我可以使用MAX一样:
SELECT * FROM a
INNER JOIN b USING(id)
WHERE b.x = (SELECT MAX(x) FROM b WHERE b.id = a.id)
使用MAX,这没有问题。但我不需要MAX。我实际上需要这样的东西:
SELECT * FROM a
INNER JOIN b USING(id)
WHERE b.x = (SELECT x FROM b
WHERE x IN (2,3,7) OR x IS NULL
ORDER BY FIELD(x,3,2,7) DESC
LIMIT 1)
此查询失败,因为我的MySQL版本在此子查询中不支持LIMIT。还有另一种方法可以确保按照我提供的顺序加入至少一行吗?
我正在尝试做的示意图概述:
Select * from table a for each id
Join table b where x = 7
If no entry in b exists where a.id=b.id and x = 7, join b where x = 2
If no entry in b exists where a.id=b.id and x IN (2,7), join b where x = 3
If no entry in b exists where a.id=b.id and x IN (2,3,7), join b where x IS NULL
我有这个需要因为:
所以,简而言之,我的问题是:是否有类似于MAX的函数可以考虑特定的顺序而不是MAX值?
提前致谢!
答案 0 :(得分:1)
您可以通过手动指定每个X的排序权重来执行此操作。
mysql> select * from aa;
+----+------+
| id | name |
+----+------+
| 1 | John |
| 2 | Ted |
| 3 | Jill |
| 4 | Jack |
+----+------+
4 rows in set (0.00 sec)
mysql> select * from bb;
+------+------+------------+
| id | x | class |
+------+------+------------+
| 1 | 7 | HighPriori |
| 1 | 2 | MediumPrio |
| 1 | 3 | LowPriorit |
| 2 | 2 | Medium |
| 2 | 3 | Low |
| 3 | 3 | Low only |
+------+------+------------+
5 rows in set (0.00 sec)
select version();
+-------------+
| version() |
+-------------+
| 5.5.25a-log |
+-------------+
SELECT aa.name, bb.x, bb.class
FROM aa LEFT JOIN bb ON (aa.id = bb.id AND bb.x IN (2,3,7)
AND bb.x = ( SELECT x FROM bb WHERE bb.id = aa.id AND x IN (2,3,7)
ORDER BY CASE
WHEN x = 7 THEN 100
WHEN x = 2 THEN 200
WHEN x = 3 THEN 300
ELSE 400
END LIMIT 1 )
);
最里面的SELECT
将根据优先级选择最合适的X值:7如果可用,否则为2,否则3.如果在这种情况下“优先级”不按顺序排列,则也可以即,7高于3,但2也高于3.
然后LEFT JOIN
将匹配该记录(如果存在)或NULL
(如果不存在)。
John有2,3和7获得7记录,而Ted有2和3,获得2:
+------+------+------------+
| name | x | class |
+------+------+------------+
| John | 7 | HighPriori |
| Ted | 2 | Medium |
| Jill | 3 | Low only |
| Jack | NULL | NULL |
+------+------+------------+
(严格地说,内部IN (2,3,7)
中的SELECT
和ELSE
中的CASE
是多余的;要么会这样做。
CASE
...... 如果X字段已经建立了订单,例如,您希望以3 - 3 - 7或7 - 3 - 2数字顺序显示值3,2,7,则可以不使用CASE
:而不是
ORDER BY CASE
WHEN x = 7 THEN 100
WHEN x = 2 THEN 200
WHEN x = 3 THEN 300
ELSE 400
END
你可以指定
ORDER BY x
或
ORDER BY x DESC
...性能改进很小,即使x被索引,但是如果你有很多X值,那么在CASE
中指定它们可能很尴尬,并且研究异常可能是冗长。
但是让我们假设您希望对象按此顺序
First Last
20,21,22,23,40,41,42,9,1,2,3,4,5
通常在X被声明为无符号且值为1-5时出现(“我们从不需要更多类,1 总是将成为第一个!”),然后几周后有人补充说“这是一个令人兴奋的新产品,必须先行!”异常并为其分配9,最后再次发生“让我们为即将推出的产品系列添加一个以2X和4X开头的全新XY类......”,你可以这样做
WHEN x <= 5 THEN 900+x
WHEN x = 9 THEN 809
ELSE 700 + x
翻译有序序列中的上述混乱集合
720,721,722,723,740,741,742,809,901,902,903,904,905
并且使用三个WHEN
来完成所有工作。
答案 1 :(得分:0)
SELECT * FROM a
INNER JOIN b USING(id)
WHERE b.x = (SELECT x FROM b
WHERE x IN (2,3,7) OR x IS NULL
ORDER BY FIELD(x,3,2,7) DESC
LIMIT 1)
将子查询切换为连接
SELECT * FROM a
join ( SELECT x FROM b
WHERE x,id IN (2,3,7) OR x IS NULL
ORDER BY FIELD(x,3,2,7) DESC
LIMIT 1) as X on X.id = a.id