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
列的数据类型为 DATE
、DATETIME
、TIMESTAMP
,或者存储在该列中的值在规范格式...较低的值对应较早的日期。
但是,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
我有这个功能多对多表。
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
列的数据类型为 DATE
、DATETIME
、TIMESTAMP
,或者存储在该列中的值在规范格式...较低的值对应较早的日期。
但是,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