Выборка нескольких строк как одну

trashcan

Новичок
Выборка нескольких строк как одну

Здравствуйте, видел когда-то на форуме похожую проблему, но, как ни старался, не смог сейчас найти ту тему. В общем, проблема такая:
Есть таблица следующего вида:

fields:
PHP:
field_id   field_name     field_value        product_id
1             Товар          Ботинки               1
2             Цена           Мильон                1
3             Товар          Омлет                 2
4             Цена           Два мильона           2
5             Товар          Омлет                 3
6             Цена           Бесплатно             3
К примеру, нужно выбрать из этой таблицы такой product_id, для которого бы Товар=Омлет, а Цена=Бесплатно.
Однако тут мы сталкиваемся с неприятной особенностью таблицы. Раз наименование товара и цена содержатся в разных строках, то условие (field_name='Товар' AND field_value='Омлет') AND (field_name='Цена' AND field_value='Бесплатно') не даст вообще ничего, а если заменить средний AND на OR, то получим вообще все Омлеты и все товары с ценой Бесплатно.
В голову не пришло ничего, кроме такого варианта:
PHP:
SELECT tab1.product_id FROM (SELECT * FROM fields WHERE field_name='Товар' AND field_value='Омлет' ) as tab1, (SELECT * FROM fields WHERE field_name='Цена' AND field_value='Бесплатно' ) as tab2 WHERE tab1.product_id = tab2.product_id;
Однако, если характеристик не две, а допустим n (Цвет, Фасон, Размер, etc), то придется объединять n-подзапросов, что имхо не есть хорошо.
Подскажите, пожалуйста, есть ли другой вариант реализации такого запроса. Заранее благодарен.
 

Bitterman

Новичок
Например, LEFT JOIN таблицы на саму себя. Однако, если характеристик n, то будет та же самая проблема - n раз сделать left join.
 

Pigmeich

Новичок
trashcan
Предлагаю поджойнить. Впрочем нечто подобное ты и сделал своим запросом, только криво.

У меня сейчас голова не работает на тему, как математически доказать необходимость N-подзапросов, но, думаю, это все-таки минимум.

-~{}~ 15.01.08 18:17:

trashcan
это не 1С случаем?
 

cDLEON

Онанист РНРСlub
Что мешает вбивать в один ряд и цену и товар?
Зачем такая извращенская структура ?
 

trashcan

Новичок
Автор оригинала: Bitterman
cDLEON
Какие еще варианты при переменном числе параметров?
Да, уж, универсальность, мать ее.

Автор оригинала: Bitterman
будет та же самая проблема - n раз сделать left join.
То есть пока в MySQL не появились подзапросы, проблема была нерешаемая?

Автор оригинала: Pigmeich
Предлагаю поджойнить. Впрочем нечто подобное ты и сделал своим запросом, только криво.
Ну и в чем кривизна? Я вообще его просто как пример возможной реализации навскидку написал. Можно конечно обойтись и одним подзапросом (ну или n-1, если параметров больше двух), но это не слишком существенно в рамках заданного мной вопроса.
 

trashcan

Новичок
Думаю разберусь, просто сразу не вник в суть ответа Bitterman.
Gas
Bitterman
спасибо.

Кстати, задумался. Чтобы обойтись без подзапросов ведь не обязательно использовать именно LEFT JOIN? По идее и простой JOIN сойдет. Разве нет?
 

Pigmeich

Новичок
trashcan
Кстати, задумался. Чтобы обойтись без подзапросов ведь не обязательно использовать именно LEFT JOIN? По идее и простой JOIN сойдет. Разве нет?
внимаетльно читай ман по разнице между этими понятиями. Кстати, join все равно подзапрос делает, так что не суть.
explain select объяснит.

Ну и в чем кривизна? Я вообще его просто как пример возможной реализации навскидку написал. Можно конечно обойтись и одним подзапросом (ну или n-1, если параметров больше двух), но это не слишком существенно в рамках заданного мной вопроса.
В том что выборка из двух таблиц (или результатов запроса) затратнее джойна.
 

cDLEON

Онанист РНРСlub
Bitterman
Ну в дампе я увидел только два поля.
Цена + Товар.
А вообще, коль на то пошло, я решил похожую задачу недавно.
Суть вот в чём:
Я засунул все костюмные данные в одну ячейку типа текст и засериализовал. И сделал таблицу для линковки. Добавил каждой модели по данным, которые нужно сохранить\искать по ним. Таблица для линковки представляет собой 6-есть проиндексированных полей. 3-варчар 3-инт и одно со ссылкой на данные в виде айдишника. И для удобства написал 2-ве функции:
http://phpclub.ru/paste/1958
 

Bitterman

Новичок
cDLEON
Честно говоря, не до конца понял твою идею. Если не сложно, кинь структуры таблиц и строчку данных для примера.
 

cDLEON

Онанист РНРСlub
PHP:
class russianBilling extends PaySystem{
	var $name 	=	"russianBilling";
	var $searchArr	=	Array("RBprefix"=>"string",Array("number_uk"=>"int","number_kz"=>"int","number_ru"=>"int"));
PHP:
		$num   =intval($_GET['num']);
		$prefix=mysql_escape_string(trim($_GET['msg']));
		if(!$row=$this->searchTarifAtLinks($prefix,$num)) {
			echo __("Тариф с префиксом: '%s' и номером:'%s' не найден!",$prefix,$num);
			return false;
		}
А структуру я уже объяснил.
Одна таблица хранит все данные в сериализованном массиве.
Вторая таблица хранит линки без названий. Просто тупо значения. И в зависимости от мадели ищет их у себя в линках.
 

Bitterman

Новичок
cDLEON
Ну не хочешь постить структуру, так не пости. Я лично, в сообщении
Я засунул все костюмные данные в одну ячейку типа текст и засериализовал. И сделал таблицу для линковки. Добавил каждой модели по данным, которые нужно сохранить\искать по ним. Таблица для линковки представляет собой 6-есть проиндексированных полей. 3-варчар 3-инт и одно со ссылкой на данные в виде айдишника.
после предложения
И сделал таблицу для линковки
вообще ничего не понял. Почему полей именно 6? Что в них содержится? Что означает предложение
Добавил каждой модели по данным, которые нужно сохранить\искать по ним.
?
Вторая таблица хранит линки без названий.
На что линки?
 

FractalizeR

Новичок
Если не менять структуру таблиц (а это неплохо бы сделать, похоже, потому что таблица не нормализована), я бы предложил такое решение:

SELECT product_id, count(product_id) AS charnum FROM fields WHERE

(field_name="Цена" AND field_value="бесплатно") OR
(field_name="Товар" AND field_value="Омлет")

GROUP BY product_id HAVING charnum = X

Где X - количество характеристик, по которым производим поиск. В данном случае - 2 (Цена + Товар)

Проверил на вашей тестовой таблице - работает вроде
 

cDLEON

Онанист РНРСlub
Bitterman
Я не нехочу. Мне просто лень отделять желчь от нужного кода.
Линки - это я так данные для модели называю... То, что лежит в названии ключей массива $searchArr - и это же будет ключём для данных. С тем же названием что и оригинальные данные, но для поиска. Посмотри в ф-и searchTarifAtLinks саму логику. Я думал, что в функции будет проще понять что к чему.
Почему именно 6 ? Потому что мои модели более чем по 6 критериям ни чего не ищут.
 

Gas

может по одной?
FractalizeR
да.

Bitterman
у cDLEON частный случай с нарушением нормализации, соответственно и решение своё.
 

cDLEON

Онанист РНРСlub
Gas
Возможно. Но как пример пойдёт. К тому же быстродействие не страдает...
 

trashcan

Новичок
Автор оригинала: Pigmeich
внимаетльно читай ман по разнице между этими понятиями.
Я про Фому, ты про Ерему. Разницу я знаю. Но в моем случае она не будет влиять на результат.

Автор оригинала: Pigmeich
Кстати, join все равно подзапрос делает, так что не суть.
Да ну? То есть, когда в MySQL еще не было механизма подзапросов, там и Join не работал.;)

Автор оригинала: Pigmeich
В том что выборка из двух таблиц (или результатов запроса) затратнее джойна.
Ты не совсем правильно выразился, но я тебя понял и в общем согласен. Только не ты ли говорил, что n подзапросов - это минимум.:cool:

FractalizeR
Спасибо, попробую.
 

Pigmeich

Новичок
Я про Фому, ты про Ерему. Разницу я знаю. Но в моем случае она не будет влиять на результат.
будет.
Да ну? То есть, когда в MySQL еще не было механизма подзапросов, там и Join не работал.
но джойны выполнялись подзапросами на нижнем уровне.
Ты не совсем правильно выразился, но я тебя понял и в общем согласен. Только не ты ли говорил, что n подзапросов - это минимум.
я и сейчас говорю, что минимум.
 
Сверху