Выборка из нескольких таблиц

Необходимо выбрать значения из трёх таблиц:
CREATE TABLE IF NOT EXISTS `hits` (
`date` date NOT NULL,
`ip` varchar(64) NOT NULL,
`offer_id` int(10) unsigned NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`hits` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`date`,`ip`),
KEY `offer_id` (`offer_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `stats` (
`date` date NOT NULL,
`payin` decimal(10,2) unsigned NOT NULL DEFAULT '0.00',
`user_id` int(10) unsigned NOT NULL,
`offer_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`date`),
KEY `user_id` (`user_id`),
KEY `offer_id``` (`offer_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `calendar` (
`date` date NOT NULL,
PRIMARY KEY (`date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Суть условий выборки приведён в псевдокоде.
Псевдокод:
select calendar.date, hits.sum(hits), stats.sum(payin)
where hits.user_id=1 and stats.user_id=1 and hits.offer_id=1 and stats.offer_id=1 and calendar.date=hits.date and calendar.date=stats=date
Предложите, пожалуйста, ваши варианты запросов.

1 ответов


Вообще-то таблицы принято соединять через join или, если нужно выбрать все строки из первой, даже если не нашлась пара во второй, через left join. И если есть групповая функция sum, должен быть group by с полями, по которым производится группировка.

select calendar.`date`, sum(hits.hits), sum(stats.payin)
from calendar
  left join hits on calendar.`date` = hits.`date`
  left join stats on calendar.`date` = stats.`date`
where calendar.`date` = '2014-01-01' and hits.user_id=1 and stats.user_id=1 and hits.offer_id=1 and stats.offer_id=1
group by calendar.`date`
Но похоже ваши таблицы никак не связаны, ни по ключу, ни по смыслу. Нет смысла их объединять.
Думаю два отдельных простых запроса будут быстрее, чем джоин таблиц, включая таблицы calendar, которая вообще не содержит полезных данных и нужна только в качестве pivot table.

Первый (group by не нужен, так как после select только суммируемое поле):
select sum(hits) from hits where `date` = '2014-01-01' and user_id=1 and offer_id=1и второй запрос (бонус: тут не нужна группировка, так как на определенную дату может быть только одна строка):
select payin from stats where `date` = '2014-01-01' and user_id=1 and offer_id=1
Первый запрос может возвращать NULL, следующие два - 0 строк. Будьте готовы обработать исключительные ситуации.

Я бы еще посоветовал переименовать поле `date`, так как date - зарезервированное слово и чтобы его использовать в запросе в качестве названия колонки, приходится брать в обратные апострофы. В запросах ограничивающие условия стоит начинать с поля date, наиболее ограничивающего условия. Можно еще поворчать по поводу хранения IP адреса. И таблица calendar, если она не нужна для каких-то иных целей, убейте ее!