2012-02-10 61 views
1

我有以下的数据库结构:复杂的MySQL数据库查询

站点表

id | name | other_fields 

备份表

id | site_id | initiated_on(unix timestamp) | size(float) | status 

所以Backups表有一个与多对一的关系Sites表通过连接


而且我想输出的格式如下

name | Latest initiated_on | status of the latest initiated_on row 

的数据和我有以下SQL查询

SELECT *, `sites`.`id` as sid, SUM(`backups`.`size`) AS size 
FROM (`sites`) 
LEFT JOIN `backups` ON `sites`.`id` = `backups`.`site_id` 
WHERE `sites`.`id` = '1' 
GROUP BY `sites`.`id` 
ORDER BY `backups`.`initiated_on` desc 

的事情是,上述查询我可以实现我在寻找的东西,但唯一的问题是我没有得到最新的initiated_on值。

所以,如果我在backups有3行与site_id = 1,查询不initiated_on挑选出具有最高值的行。它只是挑出任何一行。

请帮帮忙,并

在此先感谢。

+1

当你有一个GROUP BY时,你不应该编写SELECT * - 你将返回的值将是任意的。在大多数DB中,这甚至不是有效的SQL语句。 (即使你不使用GRUOP BY,SELECT *仍然被认为是一种不好的做法)。 – 2012-02-10 14:55:30

+0

我可以将它更改为'SELECT sites。*'? – ekhaled 2012-02-10 15:00:14

+0

你还没有在你的SELECT中加入initiate_on,这可能是为什么它没有返回它。 – CBusBus 2012-02-10 15:26:57

回答

2

你应该尝试:

SELECT sites.name, FROM_UNIXTIME(b.latest) as latest, b.size, b.status 
FROM sites 
LEFT JOIN 
    (SELECT bg.site_id, bg.latest, bg.sizesum AS size, bu.status 
    FROM 
     (SELECT site_id, MAX(initiated_on) as latest, SUM(size) as sizesum 
     FROM backups 
     GROUP BY site_id) bg 
    JOIN backups bu 
    ON bu.initiated_on = bg.latest AND bu.site_id = bg.site_id 
) b 
ON sites.id = b.site_id 
  1. GROUP BY子查询 - bg在这里,你可以使用SELECT列只有那些要么列通过函数聚合或列在GROUP BY部分。

    http://dev.mysql.com/doc/refman/5.5/en/group-by-hidden-columns.html

  2. 一旦你拥有所有你需要重新加入的结果backups找到其他值与最新时间戳的行聚合值 - b

  3. 最后将结果连接到sites表以获取名称 - 如果要列出所有网站,即使没有备份,也要将其加入。

+0

这是最有效的解决方案,但您还应该将“bu.site_id = bg.site_id”添加到最里面的连接 – nnichols 2012-02-10 16:36:45

+0

是的你是对的,我假设为int时间戳记足够独特,已编辑。 – piotrm 2012-02-10 16:43:50

+0

谢谢,很好的解释和查询在我粗略的基准测试中是高效的。 – ekhaled 2012-02-12 16:57:10

1

尝试这样的:

select S.name, B.initiated_on, B.status 
from sites as S left join backups as B on S.id = B.site_id 
where B.initiated_on = 
     (select max(initiated_on) 
      from backups 
      where site_id = S.id) 
1

要获取最新的时候,你需要做一个子查询是这样的:

SELECT sites.id as sid, 
      SUM(backups.size) AS size 
      latest.time AS latesttime 
     FROM sites AS sites 
LEFT JOIN (SELECT site_id, 
        MAX(initiated_on) AS time 
       FROM backups 
      GROUP BY site_id) AS latest 
     ON latest.site_id = sites.id 
LEFT JOIN backups 
     ON sites.id = backups.site_id 
    WHERE sites.id = 1 
    GROUP BY sites.id 
    ORDER BY backups.initiated_on desc 

我已删除了SELECT *,因为这只会使用MySQL工作,一般是不好的做法呢。如果包含其他字段(即使是单独的),非MySQL RDBS将引发错误,并且您需要将此查询本身放入子查询中,然后对网站表执行INNER JOIN以获取其余字段。这是因为他们将尝试将所有这些添加到GROUP BY语句中,如果您有长文本字段,则会失败(或者至少非常慢)。

+0

差不多.....不得不在子查询中做'GROUP BY site_id' ... – ekhaled 2012-02-10 17:12:04

+0

糟糕!这是我的想法。编辑为使用正确的列名称。 – 2012-02-10 17:41:31