#3. 通过一个组来选取第一条记录
把前面那个查询稍微变化一下:
FROM a
GROUP BY
grouper
ORDER BY
MIN(id) DESC
和前面那个查询不同,这个查询试图选出id值最小的记录。
同样:无法保证通过a.*返回的非聚合的值都属于id值最小的那条记录(或者任意一条记录)
这样做会更清晰一些:
FROM
(
SELECT DISTINCT grouper
FROM a
) ao
JOIN a
ON a.id =
(
SELECT id
FROM a ai
WHERE ai.grouper = ao.grouper
ORDER BY
ai.grouper, ai.id
LIMIT 1
)
这个查询和前面那个查询类似,但是使用额外的ORDER BY可以确保按id来排序的第一条记录会被返回。
#2. IN和‘,’——值的分隔列表
这个查询试图让column的值匹配用‘,’分隔的字符串中的任意一个值:
FROM a
WHERE column IN ('1, 2, 3')
这不会正常发挥作用的,因为在IN列表中,那个字符串并不会被展开。
如果列column是一个VARCHAR,那么它(作为一个字符串)会和整个列表(也作为一个字符串)进行比较,当然,这不可能匹配。如果 column是某个数值类型,那么这个列表会被强制转换为那种数值类型(在最好的情况下,只有第一项会匹配)
处理这个查询的正确方法应该是使用合适的IN列表来重写它:
FROM a
WHERE column IN (1, 2, 3)
或者,也可以使用内联:
FROM (
SELECT 1 AS id
UNION ALL
SELECT 2 AS id
UNION ALL
SELECT 3 AS id
) q
JOIN a
ON a.column = q.id
但是,有时这是不可能的。
如果不想改变那个查询的参数,可以使用FIND_IN_SET:
FROM a
WHERE FIND_IN_SET(column, '1,2,3')
但是,这个函数不可以利用索引从表中检索行,会在a上执行全表扫描。
#1. LEFT JOIN和COUNT(*)
FROM a
LEFT JOIN
b
ON b.a = a.id
GROUP BY a.id
这个查询试图统计出对于a中的每条记录来说,在b中匹配的记录的数目。
问题是,在这样一个查询中,COUNT(*)永远不会返回一个0。对于a中某条记录来说,如果没有匹配的记录,那么那条记录还是会被返回和计数。
只有需要统计b中的记录数目的时候才应该使用COUNT。既然可以使用COUNT(*),那么我们也可以使用一个参数来调用它(忽略掉NULL),我们可以把b.a传递给它。在这个例子中,作为一个连接主键,它不可以为空,但是如果不想匹配,它也可以为空。