2

我有一张叫做画廊的桌子。对于画廊中的每一行,表格图片中有几行。一张图片属于一个画廊。然后是桌。每一行都是对某个画廊的赞成或反对。这是(简化的)结构:

gallery ( gallery_id )
picture ( picture_id, picture_gallery_ref )
vote ( vote_id, vote_value, vote_gallery_ref )

现在我想要一个查询给我以下信息:所有画廊都有自己的数据字段和连接到画廊的图片数量和投票的汇总值。

这是我的查询,但由于多次加入,聚合值不是正确的。(至少当图片或选票超过一排时。)

SELECT 
  *, SUM( vote_value ) as score, COUNT( picture_id ) AS pictures
FROM 
  gallery
LEFT JOIN 
  vote
  ON gallery_id = vote_gallery_ref
LEFT JOIN 
  picture
  ON gallery_id = picture_gallery_ref
GROUP BY gallery_id

因为我注意到这COUNT( DISTINCT picture_id )给了我正确数量的图片,所以我尝试了这个:

( SUM( vote_value ) / GREATEST( COUNT( DISTINCT picture_id ), 1 ) ) AS score

它在这个例子中有效,但是如果一个查询中有更多的连接呢?

只是想知道是否有更好或更“优雅”的方式可以解决这个问题。另外我想知道我的解决方案是特定于 MySQL 还是标准 SQL?

4

4 回答 4

5

来自奥卡姆的威廉的这句话在这里适用:

Enita non sunt multiplicanda praeter necessitatem

(拉丁语为“实体不得在必要时成倍增加”)。

您应该重新考虑为什么需要在单个查询中完成此操作? 确实,单个查询的开销比多个查询要少,但是如果单个查询的性质变得过于复杂,无论是您开发还是 RDBMS 执行,都可以运行单独的查询。

于 2009-02-18T20:30:22.640 回答
3

或者只是使用子查询...

我不知道这是否是有效的 MySQL 语法,但您可能可以执行以下操作:

SELECT
  gallery.*, a.score, b.pictures
LEFT JOIN
(
  select vote_gallery_ref, sum(vote_value) as score
  from vote
  group by vote_gallery_ref
) a ON gallery_id = vote_gallery_ref
LEFT JOIN 
(
  select picture_gallery_ref, count(picture_id) as pictures
  from picture
  group by picture_gallery_ref
) b ON gallery_id = picture_gallery_ref
于 2009-02-18T20:42:17.150 回答
1

您多久添加/更改一次投票记录?

您多久添加/删除一次图片记录?

您多久对这些总数运行一次此查询?

在图库表 ( total_pictures, total_votes, total_vote_values) 上创建总计字段可能会更好。

当您在图片表上添加或删除记录时,您还会更新图库表上的总数。这可以使用图片表上的触发器自动更新图库表来完成。也可以使用结合两条 SQL 语句来更新图片表和图库表的事务来完成。当您在图片表上添加记录时,会增加total_pictures库表上的字段。当您删除图片表上的记录时,会减少该total_pictures字段。

类似地,当添加或删除投票记录或vote_value您更新total_votestotal_vote_values字段的更改时。添加记录会增加total_votes字段并添加vote_valuestotal_vote_values. 删除记录会减少total_votes字段并从 中vote_values减去total_vote_values。更新vote_values投票记录也应该更新 total_vote_values差异(减去旧值,添加新值)。

您的查询现在变得微不足道 - 它只是来自画廊表的简单查询。但这是以更复杂的图片和投票表更新为代价的。

于 2009-02-18T21:10:21.670 回答
0

正如比尔卡尔文所说,在一个查询中完成这一切是非常丑陋的。

但是,如果你必须这样做,使用聚合数据连接和选择非聚合数据需要连接子查询(过去几年我没有太多使用 SQL,所以我实际上忘记了这个的正确术语)。

假设您的图库表有其他字段name并且state

select g.gallery_id, g.name, g.state, i.num_pictures, j.sum_vote_values
from gallery g
inner join (
  select g.gallery_id, count(p.picture_id) as 'num_pictures'
  from gallery g
  left join picture p on g.gallery_id = p.picture_gallery_ref
  group by g.gallery_id) as i on g.gallery_id = i.gallery_id
left join (
  select g.gallery_id, sum(v.vote_value) as 'sum_vote_values'
  from gallery g
  left join vote v on g.gallery_id = v.vote_gallery_ref
  group by g.gallery_id
) as j on g.gallery_id = j.gallery_id

这将产生一个结果集,如下所示:

gallery_id, name, state, num_pictures, sum_vote_values
1, 'Gallery A', 'NJ', 4, 19
2, 'Gallery B', 'NY', 3, 32
3, 'Empty gallery', 'CT', 0, 
于 2009-02-18T20:46:50.493 回答