2012-02-10 4 views
1

У меня есть следующая структура базы данных:Сложное базы данных MySQL Query

Sites стол

id | name | other_fields 

Резервные копии таблицы

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

Так Backups таблицы имеют многие к одному отношения с Sites стол, подключенный через site_id


И я хотел бы, чтобы вывести данные в следующем формате

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 

Дело в том, с выше I запроса может достичь того, что я ищу, но единственная проблема заключается в том, что я не получаю последние значения initiated_on.

Так что если я имел 3 строки в backups с site_id = 1, запрос не выбрать строку с наибольшим значением в initiated_on. Он просто выбирает любую строку.

Помогите, и

заранее.

+1

Вы не должны писать SELECT *, когда у вас есть GROUP BY - значения, которые вы получите, будут произвольными. В большинстве БД это даже не было бы действительным оператором SQL. (И даже если вы не используете GRUOP BY, SELECT * по-прежнему считается плохой практикой). –

+0

Могу ли я изменить его на 'SELECT sites. *'? – ekhaled

+0

Вы не добавили initial_on в свой SELECT, что, вероятно, поэтому не возвращает его. – CBusBus

ответ

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

+0

Да, вы правы, я предположил, что int timestamp была достаточно уникальной, отредактирована. – piotrm

+0

Спасибо, хорошо объяснил, и запрос эффективен в моем сыром бенчмаркинге. – ekhaled

1

Try с этим:

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 RDBSs выдаст ошибку, если вы включите другие поля, даже индивидуально, и вам нужно будет сделать этот запрос сам в подзапрос, а затем сделать INNER JOIN в таблицу сайтов, чтобы получить остальные поля. Это связано с тем, что они будут пытаться добавить все из них в оператор GROUP BY, и это не сработает (или, по крайней мере, очень медленно), если у вас есть длинные текстовые поля.

+0

почти ..... пришлось сделать 'GROUP BY site_id' в подзапросе ... – ekhaled

+0

Упс! Вот что я имел в виду. Отредактировано для использования имени правого столбца. –