MySQL不确定聚合功能

时间:2016-01-12 14:39:25

标签: mysql group-by min

我有这个功能多对多表。

table Actor
-----------
Actorid     Fullname

table entertainment
-------------------------
Entertainmentid   Name   Date


Actor_entertainment
-------------------------
Entertainmentid   Actorid

我需要选择所有演员的名字,并为每个演员选择演员最早的娱乐日期和名称。

我构建了这个查询:

SELECT 
a.fullname
, c.Name
, MIN(c.Date) 
FROM Actor a 
INNER JOIN Actor_entertainment b on b.Actorid = a.Actorid 
INNER JOIN entertainment c ON c.entertainmentID = b.entertainmentID 
GROUP BY 
a.Fullname

查询效果很好,但我不确定MIN函数选择正确的日期。你可以阅读这个问题并告诉我,我错了吗?确切地说,错误是可能的吗?

感谢。

2 个答案:

答案 0 :(得分:0)

是的,将返回c.Date的最小值。只要Date列的数据类型为DATEDATETIMETIMESTAMP,或者该列中存储的值位于“{1}}列中,那么这将是”最早的日期“规范格式...较低的值对应于较早的日期。

但是,c.Name表达式返回的值是 indeterminate 。也就是说,无法保证为该表达式返回的值将来自返回最小日期值的同一行。

(其他数据库会返回一条带有该SQL语句的错误,因为出现在SELECT列表中的“非聚合”表达式而没有出现在GROUP BY子句中.MySQL为GROUP BY提供了非标准的扩展。允许此查询执行。通过将SQL_MODE设置为包含ONLY_FULL_GROUP_BY,可以修改MySQL的行为以禁用此扩展。)

有两种方法可以使Name与最早的日期相关联。

对于返回的少量行和可用的合适索引,使用相关子查询是可行的:

  SELECT a.fullname
       , ( SELECT c.Name
             FROM entertainment c
             JOIN Actor_entertainment b
               ON b.entertainmentID = c.entertainmentID 
            WHERE b.Actorid = a.Actorid
            ORDER BY c.Date ASC, c.Name ASC
            LIMIT 1
          ) AS `Name`
       , ( SELECT c.Date
             FROM entertainment c
             JOIN Actor_entertainment b
               ON b.entertainmentID = c.entertainmentID 
            WHERE b.Actorid = a.Actorid
            ORDER BY c.Date ASC, c.Name ASC
            LIMIT 1
          ) AS `Date`
    FROM Actor a
   ORDER BY a.fullname

另一种方法是获取最早的日期,然后执行连接以查找与该最早日期对应的行。如果Actor中给定行的“最小”日期不止一行,则会返回所有这些行:

  SELECT da.fullname
       , dc.Name
       , dc.Date
    FROM ( SELECT a.actorid
                , MIN(c.Date) AS min_date
             FROM Actor a
             JOIN Actor_entertainment b
               ON b.Actorid = a.Actorid
             JOIN entertainment c
               ON c.entertainmentID = b.entertainmentID
            GROUP BY a.actorid
         ) d
    JOIN Actor da
      ON da.actorid = d.actorid
    JOIN Actor_entertainment db
      ON db.Actorid = d.Actorid
    JOIN entertainment dc
      ON dc.entertainmentID = db.entertainmentID
     AND dc.Date = d.min_date

答案 1 :(得分:0)

使用变量,您可以根据日期为每位艺术家创建排名,然后只选择每位艺术家的第一位。

另请参阅使用A, B, C而不是使用别名A, AE, E来帮助理解查询。

SELECT ArtistName,
       EntertainmentName,
       Date 
FROM (
        SELECT 
            A.fullname ArtistName
          , E.Name     EntertainmentName
          , E.Date
          , (@rank := if(@prev_artist = A.fullname, 
                         @rank + 1,  -- increase rank
                         if(@prev_artist := A.fullname, --reset rank
                            0, 
                            0                       
                           )
                        )                  
           ) as ranking 
        FROM Actor A 
        INNER JOIN Actor_entertainment AE
                on A.Actorid = AE.Actorid 
        INNER JOIN entertainment E 
                ON AE.entertainmentID = E.entertainmentID 
        CROSS JOIN (select @rank := 0, @prev_artist := '') params
        ORDER BY A.Actorid, E.Date
     ) T
WHERE ranking = 1