Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: параметрический поиск
Форумы портала PHP.SU » PHP » SQL и Архитектура БД » параметрический поиск

Страниц (1): [1]
 

1. Zuldek - 05 Марта, 2014 - 09:43:38 - перейти к сообщению
Доброго времени суток.

items

id | ...


rows

id | id_item | id_row | rows_val


rows - хранит значения дополнительных параметров, id параметра (id_row) и имеет связь один к дному с таблицей items (rows.item_id = items.id)

Есть набор пар id_row и rows_val примеры реальных возможных значений:

id_row = 39 AND rows_val = 70;
id_row = 80 AND rows_val between 70 AND 90;
id_row = 37 AND (rows_val = 1 OR rows_val = 2 OR rows_val >= 4) .

Задача извлечение id из таблицы items, удовлетворяющих этим параметрам поиска (Достаточно извлечение набора id таблицы items без прочих параметров).

Изначально запрос выглядел так (названия полей изменены):

Спойлер (Отобразить)


Естественно, мускул не показывал нужные результаты при более чем одной паре r.id_row = '...' AND r.rows_val='...';

Смог найтие решеие задачи только двумя способоами:

1. С использованием sphinx, который это сможет.
2. С использованием мускула, но при каждом дополнительном параметре придётся делать дополнительный INNER JOIN:

CODE (SQL):
скопировать код в буфер обмена
  1. SELECT SQL_CALC_FOUND_ROWS i.id
  2.  
  3. FROM items i
  4.  
  5. INNER JOIN rows r ON (r.id_item = i.id AND (r.id_row = '39' AND (r.rows_val = 3 )))
  6.  
  7. INNER JOIN rows rr ON (rr.id_item = i.id AND (rr.id_row ='50' AND rr.rows_val BETWEEN '70' AND '90'))
  8.  
  9. WHERE i.moder_status='active' ....прочие фильтры по полям таблицы items.


Минус варианта понятен, — INNER JOIN при каждом дополнительном параметре поиска (а их может быть и 10).


Подскажите эффективное решение.
2. Мелкий - 05 Марта, 2014 - 10:01:12 - перейти к сообщению
Речь о том, что нужны id_item удовлетворяющие только пересечению всех условий?

Если не требуется наложение условий, по типу "для id_row=37 найти item_id, удовлетворяющие rows_val=1 и 2 одновременно", можно сделать так:
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT id_item FROM TABLE WHERE
  2. (id_row = 39 AND rows_val = 70)
  3. OR  (id_row = 80 AND rows_val BETWEEN 70 AND 90)
  4. OR (id_row = 37 AND (rows_val = 1 OR rows_val = 2 OR rows_val >= 4))
  5. GROUP BY 1 HAVING count(DISTINCT id_row)=3

count в having должен сравниваться с ожидаемым количеством условий where

С товарами можно подзапрос и переджойнить
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT * FROM items JOIN (SELECT ...) filtered_items ON id_item=items.id
3. Zuldek - 05 Марта, 2014 - 10:11:27 - перейти к сообщению
Мелкий пишет:
Если не требуется наложение условий, по типу "для id_row=37 найти item_id, удовлетворяющие rows_val=1 и 2 одновременно"

Именно это и требуется, к сожалению, но лишь для одного параметра.
То есть, допустим, есть десяток пар:
AND id_row = 37 AND rows_val = 2
AND id_row = 5 AND rows_val = 16
AND id_row = 45 AND rows_val = 'some-val'
AND id_row = 100 AND rows_val between 90 AND 54
...

И есть только один фильтр, для которого нужно:

AND id_row = 39 AND (rows_val = 2 OR rows_val = 3 OR rows_val >= 4)
(Добавление)

Вот думаю не лучше-ли сделать ещё отдельный join результирующей временной таблицы к rows для этого параметра?

CODE (SQL):
скопировать код в буфер обмена
  1. SELECT * FROM items JOIN (
  2.  
  3.     SELECT id_item FROM TABLE WHERE
  4.     (id_row = 39 AND rows_val = 70)
  5.     OR  (id_row = 80 AND rows_val BETWEEN 70 AND 90)
  6.     OR (id_row = 37 AND (rows_val = 1 OR rows_val = 2 OR rows_val >= 4))
  7.     GROUP BY 1 HAVING count(DISTINCT id_row)=3
  8.  
  9. ) filtered_items ON id_item=items.id
  10.  
  11. INNER JOIN rows rr ON item.id = rr.id_item AND (rr.rows_val = 2 OR rr.rows_val = 3 OR rr.rows_val >= 4)
4. Мелкий - 05 Марта, 2014 - 10:27:16 - перейти к сообщению
Zuldek пишет:
И есть только один дополнительный параметр (количество комнат)

Комнат ведь не может быть одновременно 2 и 3 у одного item, тогда мой вариант годится.

Например, id_row=199 - это вид из окна. val, например, представляет вид на реку, вид на лес. Мой вариант усложнится, если потребуется найти item с видом из окна на лес с рекой (т.е. одновременно виден и лес и река), а не на хотя бы что-нибудь одно из них.
5. Zuldek - 05 Марта, 2014 - 10:51:47 - перейти к сообщению
Цитата:
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT * FROM items JOIN (SELECT ...) filtered_items ON id_item=items.id


Мускел не знает о id_item в подзапросе. Не сработал join:

CODE (SQL):
скопировать код в буфер обмена
  1. SELECT SQL_CALC_FOUND_ROWS i.id, i.title FROM items i JOIN (
  2.  
  3.     SELECT r.id_item FROM rows r WHERE
  4.     (r.id_row ='50' AND r.rows_val BETWEEN 70 AND 90)
  5.     OR (r.id_row = '39' AND r.rows_val = 3)
  6.     GROUP BY 1 HAVING count(DISTINCT r.id_row)=2
  7.  
  8. ) filtered_items ON r.id_item=i.id


upd. отработал без алиасов таблиц, спасибо
Спойлер (Отобразить)


Тем не менее, получается, что сами параметры со значениями придётся извлекать отдельным запросом или ещё одним подзапросом..

 

Powered by ExBB FM 1.0 RC1