|
|
|
| Добрый день,
Столкнулся с проблемой, которую не могу сам решить.
Есть таблица, структура такая: id, total_votes, total_value. В ней хранятся результаты голосования для не зарегистрированных пользователей. Здесь id - id документа, total_votes - количество голосов, total_value - сумма оценок
Вторая таблица такая: id, doc_id, user_value. В ней данные по зарегистрированным пользователям. doc_id - id документа
Третья таблица документы, id - id документа.
Мне нужен запрос, который бы выбирал данные из трёх таблиц, при чём в одной из таблиц может не существовать данных для нужного документа. Запрос пробую такой:
SELECT
d.Id,
d.Url,
s.*,
COUNT(u.id) as u_count_id,
SUM(u.user_value) as u_user_values
FROM vb_documents f
JOIN vb_reiter s ON s.Id=f.Id
JOIN vb_reiter_guest guest ON guest.doc_id=f.Id
WHERE s.total_votes + u_count_id > 10
|
Проблема в том, что в результате запроса ничего не выбирается. Мне нужно выбирать документы, у которых больше 10 голосов. Что сделано не правильно? | |
|
|
|
|
|
|
|
для: maximum7
(10.07.2010 в 16:51)
| | В вашем варианте какая то путаница с алиасами таблиц.
Оператор WHERE работает с именами полей исходных таблиц, подключенных в операторе FROM, а не с их новыми алиасами, определёнными в текущем операторе SELECT.
> при чём в одной из таблиц может не существовать данных для нужного документа
Чтобы запись документа выбиралась вне зависимости от наличия записей в присоединяемых таблицах, вместо внутреннего соединения (INNER JOIN) нужно использовать внешнее (LEFT OUTER JOIN).
У первой и третьей таблицы отношение 1 к 1, можно совместить.
Так же можно денормализовать структуру и накапливать количество и сумму значений голосов для зарегистрированных пользователей точно таким же способом как и для незарегистрированных. А таблицу `vb_reiter` использовать для контроля, чтобы один пользователь ставил каждому документу только одну оценку. Запросы значительно упростятся, производительность должна вырости.
Для текущей структуры запрос примерно такой:
SELECT
`vb_documents`.*,
COALESCE(`vb_rg`.`total_votes`, 0) + COALESCE(`vb_r`.`total_votes`, 0) AS `total_votes`,
COALESCE(`vb_rg`.`total_value`, 0) + COALESCE(`vb_r`.`total_value`, 0) AS `total_value`
FROM
`vb_documents`
LEFT JOIN `vb_reiter_guest` AS `vb_rg`
ON `vb_documents`.`id`=`vb_rg`.`id`
LEFT JOIN
(
SELECT
`doc_id`,
COUNT(*) AS `total_votes`,
SUM(`user_value`) AS `total_value`
FROM `vb_reiter`
GROUP BY `doc_id`
) AS `vb_r`
ON `vb_documents`.`id`=`vb_r`.`doc_id`
WHERE
COALESCE(`vb_rg`.`total_votes`, 0) + COALESCE(`vb_r`.`total_votes`, 0) > 10
|
| |
|
|
|
|
|
|
|
для: sms-send
(10.07.2010 в 18:47)
| | Проблема в том, что в старой таблице для каждого документа есть только одна запись и каждая новая оценка суммируется с предыдущими. Теперь мне нужно сделать так, чтобы для каждой оценки была своя запись, таким образом я смогу их редактировать в будущем. Первая и третья таблица отличаются тем, что в первой для определения пользователя используется его id, во второй его ip адрес.
В вашем sql запросе к сожалению не смог разобраться. Зачем во втором join ещё один select? | |
|
|
|
|
|
|
|
для: maximum7
(10.07.2010 в 21:55)
| | > Первая и третья таблица отличаются тем, что...
Из первого поста:
> Третья таблица документы, id - id документа.
Про разные таблицы видимо говорим.. Я про то, что каждой строке таблицы с документами соответствует одна строка таблицы с оценками гостей.
> в первой для определения пользователя используется его id, во второй его ip адрес.
ip адреса в структуре таблицы не заметил, давайте уже называть таблицы не по номерам, а названиями.
> В вашем sql запросе к сожалению не смог разобраться. Зачем во втором join ещё один select?
Выполните его отдельно и посмотрите результат. Этот подзапрос нужен для группировки голосов зарегистрированных пользователей.
> Теперь мне нужно сделать так, чтобы для каждой оценки была своя запись
Незарегистрированные пользователи по прежнему могут голосовать?
> таким образом я смогу их редактировать в будущем.
При денормализации так же сохранится возможность редактирования, просто количество голосов и их сумма будут дополнительно храниться в обсчитанном виде, как это уже сделано в таблице `vb_reiter_guest`. | |
|
|
|
|
|
|
|
для: sms-send
(10.07.2010 в 22:00)
| | Попробовал выполнить этот запрос, не вышло, нет результата.
Структура зарегистрированных пользователей:
CREATE TABLE IF NOT EXISTS `reiter_user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL DEFAULT '0',
`user_ip` varchar(20) NOT NULL,
`user_value` int(11) NOT NULL DEFAULT '0',
`doc_id` int(11) NOT NULL DEFAULT '0',
`vote_date` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=85 ;
Одна оценка = одна запись.
Для гостей:
CREATE TABLE IF NOT EXISTS `modul_reiter` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`total_votes` int(11) DEFAULT '0',
`total_value` int(11) DEFAULT '0',
`used_ips` longtext,
PRIMARY KEY (`id`),
KEY `total_votes` (`total_votes`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=491 ;
Одна запись для документа = все голоса, например:
(248, 3, 7, 'a:3:{i:0;s:11:"93.85.56.98";i:1;s:12:"66.90.104.20";i:2;s:12:"194.8.75.105";}')
Запрос сейчас у меня такой:
SELECT
f.Id,
f.Url,
s.*,
COALESCE(s.total_votes, 0) + COALESCE(user.total_votes_user, 0) AS user_votes,
COALESCE(s.total_value, 0) + COALESCE(user.total_value_user, 0) AS user_value
FROM
documents f
LEFT JOIN modul_reiter s ON s.Id=f.Id
LEFT JOIN (
SELECT
doc_id,
COUNT(*) AS total_votes_user,
SUM(user_value) AS total_value_user
FROM modul_reiter_user
GROUP BY doc_id
) as user ON user.doc_id=f.Id
WHERE COALESCE(s.total_votes, 0) + COALESCE(user.total_votes, 0) > 10
LIMIT 0,50
|
| |
|
|
|
|
|
|
|
для: maximum7
(11.07.2010 в 11:20)
| | Вопрос снят, поправил ошибки в своём варианте запроса и всё заработало. Большое спасибо за помощь. | |
|
|
|
|