За последние 24 часа нас посетили 15559 программистов и 1619 роботов. Сейчас ищут 837 программистов ...

Помогите составить сложный запрос (JOIN)

Тема в разделе "PHP и базы данных", создана пользователем sumsum, 21 ноя 2014.

  1. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    Есть таблица товаров с привязкой к пользователю по tov_owner
    Код (Text):
    1. CREATE TABLE IF NOT EXISTS `tovar` (
    2.   `tov_id` int(10) NOT NULL AUTO_INCREMENT,
    3.   `tov_cat` int(4) NOT NULL,
    4.   `tov_nazv` varchar(100) COLLATE utf8_bin NOT NULL,
    5.   `tov_opis` text COLLATE utf8_bin NOT NULL,
    6.   `tov_owner` int(10) DEFAULT '0',
    7.   PRIMARY KEY (`tov_id`)
    8. ) ;
    Есть таблица пользователей:
    Код (Text):
    1. CREATE TABLE IF NOT EXISTS `users` (
    2.   `user_id` int(11) NOT NULL AUTO_INCREMENT,
    3.   `user_login` varchar(50) COLLATE utf8_bin NOT NULL,
    4.   `user_pass` varchar(32) COLLATE utf8_bin NOT NULL,
    5.   `user_sol` char(3) COLLATE utf8_bin NOT NULL,
    6.   PRIMARY KEY (`user_id`)
    7. ) ;
    и есть таблица отзывов, которые выставляются для пользователя
    Код (Text):
    1. CREATE TABLE IF NOT EXISTS `feedbacks` (
    2.   `feedback_id` int(2) NOT NULL AUTO_INCREMENT,
    3.   `feedback_nazv` varchar(150) COLLATE utf8_bin NOT NULL,
    4.   `feedback_text` text COLLATE utf8_bin NOT NULL,
    5.   `feedback_owner` int(10) DEFAULT '0',
    6.   `feedback_receiver` int(10) DEFAULT '0',
    7.   `time` datetime NOT NULL,
    8.   `feedback_rate` int(2) NOT NULL,
    9.   `active` int(2) NOT NULL DEFAULT '0',
    10.   PRIMARY KEY (`feedback_id`)
    11. ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=10 ;
    Задача: нужно найти все товары из tovar которые бы сортировались бы сумме feedback_rate пользователя владельца товара...

    Если честно я даже теряюсь с какой стороны подойти, это нужно два JOIN делать или как?
     
  2. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    ну чтоб три таблицы объединить нужно два джойна да. но раз есть аунер товара то зачем дергать таблицу юзеров? ради никнейма?
     
  3. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    А как сделать два джойна? Можете на примере тех таблиц что я привел показать запрос? Буду благодарен.
     
  4. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    референс мануал научиться уже наконец читать
    select fields from table join anothertableone on joinstatementone join anothertabletwo on joinstatementtwo join anothertablen on joinstatementn where statement etc...

    вместо того чтоб почитать основы реляционных баз данных и понять как вообще данные разными вариантами джойна связываются мы сидим на форуме и ждем когда за нас напишут три строки кода...
     
  5. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    поддерживаю предыдущего оратора :)

    сумсум, тебя ведь уже спрашивали почему ты используешь COLLATE utf8_bin ? так почему?
     
  6. Zuldek

    Zuldek Старожил

    С нами с:
    13 май 2014
    Сообщения:
    2.381
    Симпатии:
    344
    Адрес:
    Лондон, Тисовая улица, дом 4, чулан под лестницей
    Код (Text):
    1. SELECT t1.*, SUM(t2.feedback_rate) AS sum_rating FROM tovar t1 LEFT JOIN feedbacks t2 ON t1.tov_owner = t2.feedback_receiver GROUP BY t2.feedback_receiver ORDER BY sum_rating DESC
     
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    нельзя в одном запросе делать SELECT * и GROUP BY

    Добавлено спустя 1 минуту 51 секунду:
    и еще, хоть автор и сказал "сумма фидбека", это какая-то бессмысленная величина. наверное все-таки среднее значение фидбека.
     
  8. Zuldek

    Zuldek Старожил

    С нами с:
    13 май 2014
    Сообщения:
    2.381
    Симпатии:
    344
    Адрес:
    Лондон, Тисовая улица, дом 4, чулан под лестницей
    Неужели?

    SELECT t1.*
    GROUP BY t2.feedback_receiver

    Почему это нельзя?
     
  9. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    А почему бы и нет? :) Собственно данные в УТФ-8 а как еще их хранить?

    Добавлено спустя 9 минут 49 секунд:
    Спасибо за пример. Но теперь возникла проблема. Мне нужно получать в поиске товары и сортировать их по tov_nazv но те товары что с большим рейтингом в отзывах выводить вверху. В вашем примере оно выводит только те товары владельцы которых имеют отзывы, а нужно что бы выводило в том числе и товары без отзывов.
     
  10. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    понятно. ты просто не в курсе что такое коллейшн (настройка сравнения и сортировки). путаешь с набором символов. и к тому же необязательно расписывать кодировку для каждой колонки, достаточно один раз на таблицу.

    DEFAULT CHARSET=utf8, задаст кодировку utf8 и коллейшн по умолчанию равный utf8_general_ci — это всех устраивает обычно )))
    если ты не в курсе в чем разница между *ci и *bin, то и нет причины явно указывать что-то особенное, ящитаю.

    но я не настаиваю, конечно, дело хозяйское.
     
  11. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    Я так и делал создавал кодировку для таблицы, просто когда экспорт таблицы делаешь то пхпМайАдмин сам вставляет COLLATE utf8_bin так же как и CREATE TABLE IF NOT EXISTS
     
  12. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    про collate странно, никогда такого не наблюдал. видимо какие-то настройки у тебя хитрые.
     
  13. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    Помоги с вопросом ;) как в этом примере
    Код (Text):
    1.  
    2. SELECT t1.*, SUM(t2.feedback_rate) AS sum_rating
    3. FROM tovar t1
    4. LEFT JOIN feedbacks t2 ON t1.tov_owner = t2.feedback_receiver
    5. ORDER BY sum_rating DESC
    сделать что бы выводились не только те товары у владельцев которых есть отзывы а все, в том числе и у которых нет отзывов
     
  14. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    потому что результат непредсказуем. группировка требует строгости в наборе полей на выходе. см. очень близкую тему

    где-то такие финты просто запрещены и это правильно!!! вот пруф из офф. документации.

    Добавлено спустя 55 секунд:
    @sumsum, чтобы написать запрос, надо попытаться сформулировать его по русски и тупо перевести на английский. будет очень похоже на SQL )))

    я не понял что именно ты хочешь вывести. попробуй сформулировать без вывертов вроде "но не те которые, а наоборот", а простым языком как для слабоумных:
    "выбрать такие-то поля оттуда-то, при том что такие-то поля равны тому-то" — примерно так
     
  15. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    Код (Text):
    1. Вывести все товары
    2. из tovar
    3. отсортировать по tov_nazv и SUM(t2.feedback_rate)
    Код (Text):
    1. SELECT *
    2. FROM tovar
    3. (еще надо как то сджоинить feedbacks)
    4. ORDER BY tov_nazv, SUM(t2.feedback_rate)
    Все что я смог придумать :) Помоги

    Добавлено спустя 3 минуты 51 секунду:
    Мне нужно вывести все товары и отсортировать по tov_nazv НО те товары владельцы, которых имеют лучше отзывы в feedbacks должны выводиться выше

    скажем находим в поиске два одинаковых товара
    ложка (владелец Саша)
    ложка (владелец Маша)
    у них все одинаковое и цена и название но у Маши рейтинг 20 а у саши 5 (потому что он мудак )))) нужно Машин товар в поиске вывести первым а Сашин вторым

    Добавлено спустя 2 минуты 8 секунд:
    Добавлю еще для наглядности скажем есть еще один товар
    ложка (владелец Петя) но его вообще никто никак не оценил (его нет в таблице feedbacks). в выдаче должно идти в такой последовательности:
    ложка (владелец Маша)
    ложка (владелец Саша)
    ложка (владелец Петя)
     
  16. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    сначала надо определиться с понятием "лучшие отзывы в feedbacks". подкрадываемся издалека:
    Код (Text):
    1. SELECT
    2.   `feedback_receiver` AS `user_id`,
    3.   AVG(`feedback_rate`) AS `avg_rate`
    4. FROM `feedbacks`
    5. GROUP BY `feedback_receiver`
    6. ORDER BY 2 DESC
    правильно?
    AVG(fld) означает "среднее значение в группе", то есть сумма колонки, поделить на количество строк
    ORDER BY 2 означает "сортировать по второй колонке по убыванию"

    если этот запрос верно отражает "лучшие рейтинги", дальше давай сам — используй этот запрос (без order by) как ПОДзапрос, джойни его с чем надо и сортируй результат
     
  17. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    А почему не SUM? Хотя по большому счету в данном случае это вообще не принципиально, в результате по логике будет то же самое

    Ок, а как это все увязать к товарам? что бы выводились товары как с отзывами так и без отзывов?
     
  18. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    у тебя же пользователи к отзывам относятся как один-ко-многим. как это "то же самое"!

    вот у тебя допустим оценка по пятибальной шкале. одного перца оценили трое: на 3, на 4 и на 5. сумма будет 12. ты когда-нибудь видел оценку 12 по пятибальной шкале? а средняя оценка 4.

    короче, дальше сам. у тебя есть всё для решения.
     
  19. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    У меня трехбальная шкала:
    -1 негативный
    0 нейтральный
    1 полодительный

    Та отзывы то ладно меня интересует главный вопрос. По сортировке я как нибудь бы разобрался :) А вот как сделать что бы выводились и товары с отзывами и без - вот тут загвоздка
     
  20. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    ок, еще одна попытка. вот твоя формулировка задачи:
    то, что там не sum, а avg должно быть, я просто ставлю тебя в известность, возражалка у тебя еще не выросла.

    надо вывести данные из tovar и единственно чего там не хватает для твоей хотелки — это поля с рейтингом хозяина. решаем это через "левое объединение" товаров с тем подзапросом, который я выше для тебя сделал. левое, потому что в общем случае фидбек может быть не у всех пользователей, поэтому объединение придется сделать открытым.

    сортировку тебе хочется по двум признакам, тут нет никаких хитростей кроме приоритетов. что левее в списке order by, то оказывается более весомым.

    дальше жевать уже некуда. бери и глотай )))
     
  21. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    Что то я запутался... Делаю простую выборку из таблицы товаров:
    Код (Text):
    1. SELECT *
    2. FROM  `tovar`
    получаю количество товаров
    Код (Text):
    1. Showing rows 0 - 29 (60,376 total, Query took 0.0109 sec)
    Дальше делаю выборку с лефт джоином
    Код (Text):
    1. SELECT T.* FROM `tovar` AS T
    2. LEFT JOIN feedbacks AS F ON T.tov_owner=F.feedback_receiver
    получаю количество товаров
    Код (Text):
    1. Showing rows 0 - 29 (67,047 total, Query took 0.0050 sec)
    Правильно ли я понимаю что разница 67047-60378=6671 это то что прибавляется к таблице товаров то что нашло с отзывами?
    НО если я отдельно этот поиск сделаю то есть через INNER JOIN
    Код (Text):
    1. SELECT T.* FROM `tovar` AS T
    2. INNER JOIN feedbacks AS F ON T.tov_owner=F.feedback_receiver
    то получу результат поиска
    Код (Text):
    1. Showing rows 0 - 29 (7,624 total, Query took 0.1308 sec)
    то есть на 7624-6671=953 товара больше ... не могу понять откуда взялись эти 953 товара?

    Добавлено спустя 2 минуты 19 секунд:
    То есть разве не так должно быть Лефт Джоин = товар + Иннер Джоин?
     
  22. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.250
    Адрес:
    там-сям
    увлекательная нумерология или как заниматься куйней вместо учебы.
    +1 в моем игнор-листе )))
     
  23. sumsum

    sumsum Новичок

    С нами с:
    13 май 2014
    Сообщения:
    96
    Симпатии:
    0
    Вроде решил таки вопрос, всем спасибо за помощь ;)
    Код (Text):
    1. SELECT T.*,F.avg_rate AS avg_rate
    2. FROM `tovar` AS T
    3. LEFT JOIN (
    4. SELECT
    5.   `feedback_receiver` AS `user_id`,
    6.   AVG(`feedback_rate`) AS `avg_rate`
    7. FROM `feedbacks` AS F
    8. GROUP BY `feedback_receiver`
    9. ) AS F ON T.tov_owner=F.user_id
    10. ORDER BY F.avg_rate DESC