MySQL 不确定聚合函数

MySQL not sure about aggregation function

我有这个功能多对多表。

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 函数是否选择了正确的日期。你能读一下这个查询并告诉我我哪里错了吗?准确的说有没有可能是错误的?

谢谢。

是的,c.Date 的最小值将被 returned。只要 Date 列的数据类型为 DATEDATETIMETIMESTAMP,或者存储在该列中的值在规范格式...较低的值对应较早的日期。

但是,returned 的 c.Name 表达式的值是 不确定的。也就是说,不能保证为该表达式编辑的值 return 将来自最小日期值 return 编辑的同一行。

(其他数据库会 return 那个 SQL 语句的错误,在出现 SELECT 列表但没有出现在 [=18= 中的 "non-aggregate" 表达式时犹豫不决] 子句。MySQL 为 GROUP BY 提供 non-standard 扩展,允许执行此查询。可以修改 MySQL 的行为,以禁用此扩展,方法是设置 SQL_MODE包括 ONLY_FULL_GROUP_BY.)

有几种方法可以获取与该最早日期关联的 Name

对于return编辑的少量行,以及可用的合适索引,使用相关子查询是可行的:

  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 中的给定行有多个具有相同 "minimum" 日期的行,这将 return 所有这些行:

  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

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

另请参阅,我没有使用别名 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