PDA

View Full Version : [sql] 'связанный' Select


linky
05.06.2007, 17:04
Здравствуйте. Передо мной встала задача сделать модуль с товарами, этакий каталог. В базе имеется несколько таблиц, в частности:

brands [ id | title ] - торговые марки

items [id | brand | title | description | price | category ] - сами товары

в поле brand, таблицы items, находится id бренда из таблицы brands
В самом же каталоге, мне нужно упорядочить товары сначала по названию бренда, а потом уж по наименованию товара. Вот как примерно это выглядит сейчас:

SELECT * FROM items WHERE category = '1' ORDER BY title
в данном случае, мой список товаров выглядит вот так:

3Brand - Арбуз
4Brand - Бутылка
1Brand - Венигрет
8Brand - Вертолет
5Brand - Корова
4Brand - Сумка

а вот что мне нужно:


1Brand - Венигрет
3Brand - Арбуз
4Brand - Бутылка
4Brand - Сумка
5Brand - Корова
8Brand - Вертолет

Но как упорядочить по имени бренда, если в таблице товаров есть только его id? Я в sql новичек, но уверен что это реально.
Я пробовал с помощью двух while {} где сначала перебираются все бренды, а из них выбираются только товары которые подходят к этой категории, но проблема в быстродействии - она упала очень сильно, страница грузилась очень долго, ибо брендов действительно много, около 300 штук, и сервер перебирает все товары, смотря на их категорию... вобщем это не выход, и я уверен что можно все просто одним хитрым sql-запросом все это дело упорядочить. Спасибо!

Astrix
05.06.2007, 21:22
если я правильно понял, то в таблице items поле brand соответствует полю id таблицы brands, так?
тогда можно попробовать вот такую штуку:

SELECT i.id, i.brand, i.title, i.description, i.price, i.category, b.title AS brandname FROM items AS i LEFT JOIN brands AS b ON (i.category = '1' AND i.brand = b.id) ORDER BY b.title, i.title

вариант не из лучших, конечно. но это первое, что в голову пришло. кстати в полученном масииве элемент brandmane будет соответствеовать названию бренда из таблички brands, так же желательно поиндексировать поля brand и category таблички items


вроде бы запрос получается довольно быстрый - в среднем для этого запроса MySQL понадобится перебрать n*2 записей, где n - это количество товаров категории 1 (при условии индексации нужных полей - см выше), но с учетом сортировки он может стать гораздо медленнее. но это уж точно будет в разы быстрее, нежели чем сортировка в PHP...

linky
06.06.2007, 13:13
Вау, спасибо, Astrix! Сегодня постараюсь проверить этот способ, надеюсь получится :smile:

Не, знаете, я по-разному попробовал, но не получилось того что мне нужно. Я честно говоря немного запутался. Не могли бы Вы немного мне разжевать Ваш запрос? Мне если четсно, нужно только id товара выделить, что-то типа такого:

SELECT i.id, b.title AS brandname FROM items AS i LEFT JOIN brands AS b ON (i.category = '1' AND i.brand = b.id) ORDER BY b.title, i.title

только чтобы работало)

и я не понял зачем нужно значение brandname, это для mysql_fetch_row, верно?

Astrix
06.06.2007, 19:44
Вау, спасибо, Astrix! Сегодня постараюсь проверить этот способ, надеюсь получится :smile:

Не, знаете, я по-разному попробовал, но не получилось того что мне нужно. Я честно говоря немного запутался. Не могли бы Вы немного мне разжевать Ваш запрос? Мне если четсно, нужно только id товара выделить, что-то типа такого:

SELECT i.id, b.title AS brandname FROM items AS i LEFT JOIN brands AS b ON (i.category = '1' AND i.brand = b.id) ORDER BY b.title, i.title

только чтобы работало)

и я не понял зачем нужно значение brandname, это для mysql_fetch_row, верно?


Так, ну насчет разжевать.... постараюсь :). Этот запрос выбирает все записи из таблицы items, у которых category = '1', и для каждой по идентификатору выбирает бренд i.brand = b.id.

ON (i.category = '1' AND i.brand = b.id) - это в принципе одно и то же, что и если написать WHERE i.category = '1' AND i.brand = b.id
и.... правильнее было бы сделать так:

SELECT i.id, b.title AS brandname FROM items AS i LEFT JOIN brands AS b ON (i.brand = b.id) WHERE i.category = '1' ORDER BY b.title, i.title

i и b - это, так сказать, псевдонимы таблиц items и brands соответственно. Они нужны из-за того что в этих таблицах есть одинаковые поля - id и title и обратиться к ним только по названию нельзя. хотя можно было вместо псевдонимов использовать и полные названия таблиц, но это не рационально, имхо.

к примеру, i.id - это поле id таблицы items, а b.id - поле id таблицы brands
b.title AS brandname - здесь я обозвал поле title таблицы brands как brandname, т. к. такое поле (title) уже есть в items.
а раз вам нужен только id, то нет смысла переименовывать поле и можно упростить еще немного завпрос:

SELECT i.id, b.title FROM items AS i LEFT JOIN brands AS b ON (i.brand = b.id) WHERE i.category = '1' ORDER BY b.title, i.title

ну, с ORDER BY b.title, i.title, думаю все понятно? тут идет сортировка сначала по заголовкам брендов, а потом по заголовкам продуктов (ну, или что там у вас)

и да. все названия после SELECT используются после вызова mysql_fetch_row как идентификаторы элементов получившегося массива

то есть в вашем случае это будут id продукта и title бренда

linky
07.06.2007, 21:33
Так-так-так... кто-то тут у нас гений!!! Спасибо ОГРОМНОЕ!!! СПАСИБО! Все заработало как мне надо, теперь полнейший порядок! :jumplol:

Вы, Astrix, сподвигли меня купить себе книгу по скулу, всетаки чертовски полезно его знать хорошо. Спасибо еще раз :wink: