技术开发 频道

与你预想的不一样的MySQL的10件事

  #3. 通过一个组来选取第一条记录

  把前面那个查询稍微变化一下:

SELECT  a.*  
FROM    a  
GROUP BY        
      grouper  
ORDER BY        
      MIN(id) DESC

 

  和前面那个查询不同,这个查询试图选出id值最小的记录。

  同样:无法保证通过a.*返回的非聚合的值都属于id值最小的那条记录(或者任意一条记录)

  这样做会更清晰一些:

SELECT  a.*  
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的值匹配用‘,’分隔的字符串中的任意一个值:

SELECT  *  
FROM    a  
WHERE   column IN (
'1, 2, 3')

 

  这不会正常发挥作用的,因为在IN列表中,那个字符串并不会被展开。

  如果列column是一个VARCHAR,那么它(作为一个字符串)会和整个列表(也作为一个字符串)进行比较,当然,这不可能匹配。如果 column是某个数值类型,那么这个列表会被强制转换为那种数值类型(在最好的情况下,只有第一项会匹配)

  处理这个查询的正确方法应该是使用合适的IN列表来重写它:

SELECT  *  
FROM    a  
WHERE   column IN (
1, 2, 3)

 

  或者,也可以使用内联:

SELECT  *  
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:

SELECT  *  
FROM    a  
WHERE   FIND_IN_SET(column,
'1,2,3')

 

  但是,这个函数不可以利用索引从表中检索行,会在a上执行全表扫描。

  #1. LEFT JOIN和COUNT(*)

SELECT  a.id, 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传递给它。在这个例子中,作为一个连接主键,它不可以为空,但是如果不想匹配,它也可以为空。

0
相关文章