Поможите с запросом
12 | 1967 | 5
12 | 1967 | 4
13 | Россия| 5
13 | США | 4
...
Требуется выбрать из неё vehicle_id у которого некоторые parameter_id имеют некое value. То есть, чтобы при параметрах parameter_id=12 и value=1967 и parameter_id=13 и value= Россия выборка была- vehicle_id= 5, а не 5 и 4. То есть нужно выбирать параметры с общим значением какого-то третьего параметра.
`t1`.`vechile_id`
FROM
`vechiles` AS `t1` LEFT JOIN `vechiles` AS `t2`
ON
(
`t2`.`vechile_id` = `t1`.`vechile_id`
AND
`t2`.`parameter_id` = 13
AND
`t2`.`value` = 'Россия'
)
WHERE
`t1`.`parameter_id` = 12
AND
`t1`.`value` = '1967'
Можешь где опечатался.. А может и вовсе ошибся, но у себя создал таблицу, проверил— все ок. Для t1 ищешь первую пару, для t2— вторую. "Третьим" параметром, а точнее критерием отбора пар строк служит значение поля vechile_id. Если вторая половина условия не выполняется, то есть если записи где parameter_id = 13 и value = 'Россия' нет результат все-равно выберется. Если нужно изменить такое поведение, а точнее заставить запрос браковать неполные пары строк то замени LEFT JOIN на INNER JOIN.
12 | 1967 | 5
12 | 1967 | 4
13 | Россия| 5
13 | США | 4
Просто
"Select vehicle_id From table Where parameter_id = 'value' And (value = '1' Or value = '2' Or value = '3')"
added: А вообще лучше поподробней обрисуй структуру базы и намечаемую методику фильтрации результатов— может полегче будет вникнуть)ъ К примеру, а нужен ли parameter_id? Если это таблица параметров по авто, то parameter_id это наверное просто pk, для update'ов и delete'ов? Тогда нам нужно работать только с value и получать vechile_id. Или же это не первая, а очередная ступень в отборе, и нужно ориентироваться именно по parameter_id?
added: Все, понял в чем ошибся. Вопрос по parameter_id отпадает=))
Значит выборку нужно организовывать примерно по такому принципу:
VID = select vechile_id from vechiles where parameter_id = A and value = a
VID = select vechile_id from vechiles where parameter_id = B and value = b and vechile_id in VID
VID = select vechile_id from vechiles where parameter_id = C and value = c and vechile_id in VID
...
VID = select vechile_id from vechiles where parameter_id = H and value = h and vechile_id in VID
Гм, кроме как join'ами или последовательными выборками даже и не знаю как сделать)ъ Вложенные селекты в счет не берем ведь ??, ну их в пень;)
А как СУБД кстати?
Есть 4 основных таблы-
1- категории
2- параметры категорий
3- масынки
4- параметры масынок
Создаем категорию, создаем или наследуем для неё параметры(параметров может быть хоть сколько и все они хранятся в базе "параметры категорий").
Далее создаем масынку, заполняем её параметры(параметры берутся из параметров категории к которой относится масынка). Ну и дальше по круги или пропуская первые два у нас получается много категорий и машинок в них с разными параметрами.
Например у категории "легковые" могет быть параметры: количество ДТП, количество хозяев...-, а у категории "грузовые" могут быть параметры: страна изготовитель, обем движка...ну, не важно :)
Далее пользователь заходит в какую-нибудь категорию, например легковые и выбирает необходимые ему значения параметров. Скрипт их получает и ищет в табле "параметры машинок" совпадения. По идее надо найти такой vehicle_id у которого все эти параметры(которые выбрал пользователь) присутствуют.
Если делать несколько выборок, то пользователь встанет и уйдет :) (примерный размер базы- 500000 тс,=> примерный размер таблы параметров, > 4000000)
parameter_id здесь выступает в роли индекса, по нему идет вся основная выборка. Хотя апдейт тоже по нему-же. parameter_id наследуеся от таблы "параметр категории"- при создании машины.
Толmrj с value не получиться работать, т.к. так не узнать какой параметр имеет какое значение.
// это мне сказали подобие mobile.de написать...
У тебя есть допустим 5 параметров авто.
Тебе надо найти тачку с такими параметрами.
Если так то все это можно сделать одним запросом на мускуль.
Select p1.id
From
table p1,
table p2,
table p3,
table p4,
table p5
Where
p1.id = p1.id And
p2.id = p1.id And
p3.id = p1.id And
p4.id = p1.id And
/*
id = vehicle_id(сократил шоб не парится)
потом циклом собираеш все свои параметры
*/
foreach($param as $param_id=>$param_value) {
$i++;
$sql.= "
p$i.parameter_id = '$param_id' And
p$i.value = '$param_value'";
};
Потом еще, нужно придумать как вести журнал для еще какой-никакой оптимизации выборок. Суть его заключается в том, что в нем хранятся данные по разбросу значений для определенного параметра. Можно вести такой журнал только для каждой отдельной марки автомобилей, страны или еще чего, или же для всех уровней по-отдельности.. не знаю.. Но вести это дело нужно, чтобы знать в какой последовательности выбирать, в случае последовательной выборки, или вносить в запрос, в случае использования join'ов, строки по имеющимся условиям. Может mysql И умеет делать такие оптимизации, но что-то я сомневаюсь.
Вариант ,,,,,,, ,имхо, сожрет много больше ресурсов т.к. мы получим произведение всех используемых копий таблиц, а потом из полученных результатов начнем отбирать те строки, какие нам больше приглянутся, вместо того чтоб уже на этапе вычисления произведения отбрасывать весь мусор.
Народ, вы меня пугаете :D
SELECT vehicle_id, COUNT(vehicle_id) as c FROM ... WHERE parameter_id IN() AND value IN () GROUP BY value, parameter_id, vehicle_id;
После загоняем в массив и удаляем все записи с 'c'<2, на чем собственно можно и остановиться.
2Shiizoo, спасибо, твоим способом действительно быстрее получается :) Сейчас думаю над каим-нибудь кешированием, пока додумался лишь до записи в отдельную таблу некого хеша параметров и разультатов.
Неа, не то. При таком расскладе будем получать ошибочные данные, например если у одной машины один параметр имеет id=23 и равен 33, а другой параметр имеет id=44 и значение равное 55 при этом у второй машинки этиже параметры имеют значения 55 и 66, то по условию пройдут обе эти машинки :) В общем, не катит.
А ты пробовал???? Или по твоему хитрый GROUP по нескольким полям я от скуки вставил???
Вот такой селект
на вот такой вот таблице
`parameter_id` int(10) unsigned NOT NULL default '0',
`value` varchar(255) NOT NULL default '',
`vehicle_id` int(10) unsigned NOT NULL default '0',
KEY `value` (`value`),
KEY `parameter_id` (`parameter_id`)
) TYPE=MyISAM;
--
-- Дамп данных таблицы `vehicle_parameters`
--
INSERT INTO `vehicle_parameters` (`parameter_id`, `value`, `vehicle_id`) VALUES (69, 'Пермь', 7);
INSERT INTO `vehicle_parameters` (`parameter_id`, `value`, `vehicle_id`) VALUES (68, '234', 7);
INSERT INTO `vehicle_parameters` (`parameter_id`, `value`, `vehicle_id`) VALUES (67, '435', 7);
INSERT INTO `vehicle_parameters` (`parameter_id`, `value`, `vehicle_id`) VALUES (66, '334', 7);
INSERT INTO `vehicle_parameters` (`parameter_id`, `value`, `vehicle_id`) VALUES (69, 'Москва', 12);
INSERT INTO `vehicle_parameters` (`parameter_id`, `value`, `vehicle_id`) VALUES (68, '234', 12);
INSERT INTO `vehicle_parameters` (`parameter_id`, `value`, `vehicle_id`) VALUES (67, '44', 12);
INSERT INTO `vehicle_parameters` (`parameter_id`, `value`, `vehicle_id`) VALUES (66, '66', 12);
Возвращает все ряды почему-то.
0 and c in ('audi'))) group by a having d > 1
a - vechile_id, b - parameter_id, c - value, d - сигнализирует о количестве условий из заданных которым отвечает данная группа строк, where b - здесь b это таблица.
В предложении having d > 1 число (единицу) нужно заменить на "количество условий минус 1", у меня условия было 2: количество аварий 'b = 2 and c between 0 and 7' от 0 до 7 и марка автомобиля 'b =
0 and c in ('audi')' audi, поэтому и единица.
Да, забыл. Условия как видно из примера нужно пихать в where, перечислять отдельные параметры через and, а варианты значений для них через or, between, in и т.п.
Не ручаюсь вообще-то за правильность, совсем, но может заработает. У себя протестить пока не могу. А вообще chigevara по-моему самый правильный курс держит, хотя это тоже imho.. ;)
added: Седня кстати первый день учился^^, в смысле вообще, в вузе) Весело, интересно, за раз препод по прогр. научил меня уважать pascal.. сижу щас зубрю;)
А вообще chigevara по-моему самый правильный курс держит, хотя это тоже imho.. ;)
Команданте лоханулся не по детски, что говорит о том что процесс взросления идет и не стоит на месте :D
SELECT DISTINCT a.vehicle_id as vehicle_id FROM vehicle_parameters a, vehicle_parameters b WHERE a.parameter_id IN('69','68','67') AND a.value IN ('Пермь','234','435') AND b.parameter_id IN('69','68','67') AND b.value IN ('Пермь','234','435') AND a.vehicle_id = b.vehicle_id ;
Работает(вроде)
По выложенному дампу возвращает 7 и 12.
Команданте, меня терзают смутные сомнения по поводу distinct.. Не стормознет?
Что было выше:
group by a having d > 1;
Еще раз проверил, работает. Оптимальнее пока ничего не придумывается. Ковырял ковырял join'ы, и заметил что во многих случаях это один и тот же запрос что и where только немного по-разному оформленный.
ps: не бить, туплю.
Команданте, меня терзают смутные сомнения по поводу distinct.. Не стормознет?
Дык, по одному полю ведь, не должно...
AND
a.value IN ('Пермь','234','435')
AND
b.parameter_id IN('69','68','67')
AND
b.value IN ('Пермь','234','435')
это жжж
(a.parameter_id = 69; a.value = '234')
(a.parameter_id = 69; a.value = '435')
(a.parameter_id = 68; a.value = 'Пермь')
(a.parameter_id = 68; a.value = '234')
(a.parameter_id = 68; a.value = '435')
(a.parameter_id = 67; a.value = 'Пермь')
(a.parameter_id = 67; a.value = '234')
(a.parameter_id = 67; a.value = '435')
...
(b.parameter_id = 67; b.value = '435')
Не пойму кто из вас не того ищет, или это я не того ожидаю..
В общем я думаю не протестив все варианты, хорошенько, к выводу что лучше прийти сложно. По большому счету, distinct откидывает все повторяющиеся vehicle_id.. Having с Group by несут ту же нагрузку, но...
пока (результ_строка = следующая(результ_строки)) {
флаг = 0;
сбросить_указатель(строки_на_выход);
пока (строка_на_выход = следующая(строки_на_выход)) {
если
результ_строка->vehicle_id == строка_на_выход->vehicle_id
то флаг = 1 и выход из цикла;
}
если флаг == 0 то
строки_на_выход[] = результ_строка;
}
:D ну, типа того. Я having'ом проверяю D и бракую строки сравнивая D с константой, которую задаю на этапе формирования запроса (еще за пределами субд), а distinct'у, даже если он строит какой-то индекс отбирая и бракуя строки, все же делает множество сравнений.. вот.. ну это так, мысля из воздуха, я mysql не писал - не знаю :D
Так чем все кончилось? Самому интересно непомерно;)
Закончилось тем, что я сейчас пришел на работу и буду проводить соревнования между способами. О результатах сообще дополнительно. Всем спосибо :)
// блин, трудно учится и работать, хотя труднее всеже учиться.
Есть mysql таблица вида
12 | 1967 | 5
12 | 1967 | 4
13 | Россия| 5
13 | США | 4
...
Требуется выбрать из неё vehicle_id у которого некоторые parameter_id имеют некое value. То есть, чтобы при параметрах parameter_id=12 и value=1967 и parameter_id=13 и value= Россия выборка была- vehicle_id= 5, а не 5 и 4. То есть нужно выбирать параметры с общим значением какого-то третьего параметра.
WHERE p1.vehicle_id=p2.vehicle_id
AND p1.parameter_id=12 AND p1.value="1967"
AND p2.parameter_id=13 AND p2.value="Россия"
Ответа я не видел, но напрасно, имхо, считать что он будет положительным;)
WHERE p1.vehicle_id=p2.vehicle_id
AND p1.parameter_id=12 AND p1.value="1967"
AND p2.parameter_id=13 AND p2.value="Россия"
дамс, похоже ты просто решил запостить свой вариант не прочитавне поста выше. Если что то такой вариант уже был ! ):):)
дамс, похоже ты просто решил запостить свой вариант не прочитавне поста выше. Если что то такой вариант уже был ! ):):)
Это не вариант. А решение. :)
Если ты имеешь в виду это(ошибки исправлены :)),
Select p1.id
From
table p1,
table p2,
table p3,
table p4
Where
p2.id = p1.id And
p3.id = p1.id And
p4.id = p1.id
то здесь только соединения, и нет ограничений, на записи отдельных таблиц.
...
:D ну, типа того. Я having'ом проверяю D и бракую строки сравнивая D с константой, которую задаю на этапе формирования запроса (еще за пределами субд), а distinct'у, даже если он строит какой-то индекс отбирая и бракуя строки, все же делает множество сравнений.. вот.. ну это так, мысля из воздуха, я mysql не писал - не знаю :D
Декартово произведение (слон) с прогоном where "то,сё,это" работает медленее where+group+having связки по одному экземпляру таблицы. Проверил— проигрыш декартова растет с увеличением объема данных. Это про mongoose'ов вариант.;) А вообще надо проверить это дело на сильно разреженной таблице, я-то тестил на таблице где в строках просто периодически меняются значения пары столбцов;)
... Это про mongoose'ов вариант.;) А вообще надо проверить это дело на сильно разреженной таблице, я-то тестил на таблице где в строках просто периодически меняются значения пары столбцов;)
Сколько раз повторять, что это не вариант, а решение? :)
Мимоходом, можно взглянуть на супер-пупер where+group+having SELECT?
Сколько раз повторять, что это не вариант, а решение? :)
Мимоходом, можно взглянуть на супер-пупер where+group+having SELECT?
А ты, стесняюсь спросить, топик собственно читал? Или не барское это дело :D
Сколько раз повторять, что это не вариант, а решение? :)
Мимоходом, можно взглянуть на супер-пупер where+group+having SELECT?
Хех, решение нашли сразу. По первому вопросу. А сейчас ищем способ оптимизации времени выполнения, нагрузки и т.п. В общем чем меньше напряга машине - тем лучше.
Where+group+having уже не один раз проскакивал, я даже схему работы объяснил;) Вывод - нужно читать посты треда, если постишь сам.
A— таблица.
a— vechile_id
b— parameter_id
c— value
n— количество кортежей для конкретного vechile_id удовлетворяющих условию
parameter_id 1 - страна
parameter_id 2 - марка
ищем audi в России или на Украине
a, count(*) n
from
A
where
(b = 1 and c = 'audi')
or
(b = 2 and c in ('Russia','Ukraine'))
group by a
having n > 1
Единица здесь это количество условий (у нас их два к примеру) - 1. Для двух - 1, для трех - 2.. и т.п.
ps: идея команданте, додумка моя;) но все-равно кажись какой-нибудь изящный join может проделать эту работы эффективнее.
Хех, решение нашли сразу. По первому вопросу. А сейчас ищем способ оптимизации времени выполнения, нагрузки и т.п. В общем чем меньше напряга машине - тем лучше.
Where+group+having уже не один раз проскакивал, я даже схему работы объяснил;) Вывод - нужно читать посты треда, если постишь сам.
A— таблица.
a— vechile_id
b— parameter_id
c— value
n— количество кортежей для конкретного vechile_id удовлетворяющих условию
parameter_id 1 - страна
parameter_id 2 - марка
ищем audi в России или на Украине
a, count(*) n
from
A
where
(b = 1 and c = 'audi')
or
(b = 2 and c in ('Russia','Ukraine'))
group by a
having n > 1
Единица здесь это количество условий (у нас их два к примеру) - 1. Для двух - 1, для трех - 2.. и т.п.
ps: идея команданте, додумка моя;) но все-равно кажись какой-нибудь изящный join может проделать эту работы эффективнее.
Я читал пред посты. И только потому предложил свое р е ш е н и е, что having+group таковым не является.
Например. для последнего варианта. Если есть 2 записи с
(b = 1 and c = 'audi') и для ОБОИХ a = 4
но нет ни одной записи
(b = 2 and c in ('Russia','Ukraine')) для которой a = 4
тогда having group вернет в качестве результата
4, хоть это будет неправильно.
А ты, стесняюсь спросить, топик собственно читал? Или не барское это дело :D
Читал. А твои ответы вообще на изусть выучил. :D
а вообще, во-первых where+group+having что-то стал проигрывать 1 секунду на 1,500,000 строках, но мне это уже не нравится) А твой вариант, переделанный теперь уже, это и есть inner join on .... Хоть ты и изобразил его по-другому, а mysql оптимизациями приводит его, твой запрос, и его:
`t1`.`vechile_id`
FROM
`vechiles` AS `t1` LEFT JOIN `vechiles` AS `t2`
ON
(
`t2`.`vechile_id` = `t1`.`vechile_id`
AND
`t2`.`parameter_id` = 13
AND
`t2`.`value` = 'Россия'
)
WHERE
`t1`.`parameter_id` = 12
AND
`t1`.`value` = '1967'
мой первый вариант.. в общем к одному виду их приводит. если конечно left join на inner заменить как я грил. придумывался запрос когда еще сабж не был ясен.
и в общем.. в общем.. в итоге пришли к тому, что было в начале:D жаль потраченных 2-ух часов, сейчас вот, которые мог проспать.. а-то ведь скоро вставать на учебу;)
ууу.. ночь, ползу спать и уже не соображаю;) у меня все варианты прежде сходились, щас больше ниче проверять уже не буду.. завтре;) почему group+having вернет? group по a = 4, считаем группу, отбрасываем по having > n и получаем то что нужно.
для a = 4 count() = 2.
Или уже и я тоже не соображаю???
i a b c
1 1 1 'Russia'
2 1 2 'audi'
3 2 1 'Usa'
4 2 2 'dodge
5 3 1 'Germany'
6 3 2 'audi'
7 4 1 'Ukraine
8 4 2 'audi'
по where выбираем 1,2,6,7,8
по group получаем (1,2),(6),(7,8)
по count получаем (1,2) => 2, (6) => 1, (7,8) => 2
по having получаем a = 1,4
это конечно при условии что у нас составной unique по (a,b).
ps: вот теперь сплю:angel: спокойной ночи;)