Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Сложная выборка из трёх таблиц
 
 автор: maximum7   (10.07.2010 в 16:51)   письмо автору
 
 

Добрый день,

Столкнулся с проблемой, которую не могу сам решить.

Есть таблица, структура такая: 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 голосов. Что сделано не правильно?

  Ответить  
 
 автор: sms-send   (10.07.2010 в 18:47)   письмо автору
 
   для: 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

  Ответить  
 
 автор: maximum7   (10.07.2010 в 21:55)   письмо автору
 
   для: sms-send   (10.07.2010 в 18:47)
 

Проблема в том, что в старой таблице для каждого документа есть только одна запись и каждая новая оценка суммируется с предыдущими. Теперь мне нужно сделать так, чтобы для каждой оценки была своя запись, таким образом я смогу их редактировать в будущем. Первая и третья таблица отличаются тем, что в первой для определения пользователя используется его id, во второй его ip адрес.

В вашем sql запросе к сожалению не смог разобраться. Зачем во втором join ещё один select?

  Ответить  
 
 автор: sms-send   (10.07.2010 в 22:00)   письмо автору
 
   для: maximum7   (10.07.2010 в 21:55)
 

> Первая и третья таблица отличаются тем, что...

Из первого поста:
> Третья таблица документы, id - id документа.
Про разные таблицы видимо говорим.. Я про то, что каждой строке таблицы с документами соответствует одна строка таблицы с оценками гостей.

> в первой для определения пользователя используется его id, во второй его ip адрес.
ip адреса в структуре таблицы не заметил, давайте уже называть таблицы не по номерам, а названиями.

> В вашем sql запросе к сожалению не смог разобраться. Зачем во втором join ещё один select?
Выполните его отдельно и посмотрите результат. Этот подзапрос нужен для группировки голосов зарегистрированных пользователей.

> Теперь мне нужно сделать так, чтобы для каждой оценки была своя запись
Незарегистрированные пользователи по прежнему могут голосовать?

> таким образом я смогу их редактировать в будущем.
При денормализации так же сохранится возможность редактирования, просто количество голосов и их сумма будут дополнительно храниться в обсчитанном виде, как это уже сделано в таблице `vb_reiter_guest`.

  Ответить  
 
 автор: maximum7   (11.07.2010 в 11:20)   письмо автору
 
   для: 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:55)   письмо автору
 
   для: maximum7   (11.07.2010 в 11:20)
 

Вопрос снят, поправил ошибки в своём варианте запроса и всё заработало. Большое спасибо за помощь.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования