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 и Архитектура БД » построение "хлебных крошек" одним запросом

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

1. DlTA - 16 Декабря, 2011 - 13:55:13 - перейти к сообщению
допустим имеем табличку
`каталог`
`ид` | `название` | `родитель`

если родитель =0 то эти разделы в корне,
и на них ссылкются другие разделы

как получить "хлебные крошки" "ветвь дерева" одним запросом?
запрос:
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT * FROM `каталог`, `каталог` AS `предок` WHERE
  2. `каталог`.`родитель` = `предок`.`ид`
даст ссылку только на родительский раздел
а хотелось бы всю ветвь до корня и одним запросом.
2. OrmaJever - 16 Декабря, 2011 - 14:06:30 - перейти к сообщению
рекурсия
3. tuareg - 16 Декабря, 2011 - 14:09:56 - перейти к сообщению
Если у Вас неограниченное количество вложений, то в данном варианте никак.
Если знаете сколько вложений то нужно связать столько таблиц сколько вложений.
4. EuGen - 16 Декабря, 2011 - 14:10:02 - перейти к сообщению
Самое простое в такой ситуации - хранить отдельно полный путь (в упорядоченном виде) для каждого элемента в отдельном поле. Имеет свои минусы - при изменении структуры нужно перестраивать.

Иным решением станет хранение дополнительно позиции. Здесь пример:

http://stackoverflow[dot]com/questio[dot][dot][dot]-for-nested-sets
5. DlTA - 16 Декабря, 2011 - 16:41:11 - перейти к сообщению
OrmaJever пишет:
рекурсия
это каждый раз новый запрос, не катит

tuareg пишет:
Если знаете сколько вложений то нужно связать столько таблиц сколько вложений.
а это все равно как минимум 2 запроса.

EuGen пишет:
Иным решением станет хранение дополнительно позиции. Здесь пример:
http://stackoverflow.com/questio...-for-nested-sets

этот?
CODE (text):
скопировать код в буфер обмена
  1. ID   Name    ParentId  Left   Right   Path
  2. 0    Node A  0         1      12      0,
  3. 1    Node B  0         2      5       0,1,
  4. 2    Node C  1         3      4       0,1,2,
  5. 3    Node D  0         6      11      0,3,
  6. 4    Node E  3         7      8       0,3,4,
  7. 5    Node F  4         9      9       0,3,4,

CODE (SQL):
скопировать код в буфер обмена
  1. path = SELECT Path FROM Nodes WHERE ID = 3
  2. SELECT * FROM Nodes WHERE Path LIKE = path + '%'


а как работает это услови? WHERE Path LIKE = path + '%'
6. tuareg - 16 Декабря, 2011 - 18:47:58 - перейти к сообщению
DlTA завтра если время будет посмотрю свой вариант.
По факту там только один запрос. Но надо знать сколько вложений
7. Champion - 16 Декабря, 2011 - 18:57:15 - перейти к сообщению
Если бы это был Postgres, Firebird, Oracle, MS SQL Server, то можно было бы вытянут рекурсивным запросом с WITH.

А поскольку речь, видимо о мускуле, то кроме предложенных вариантов еще вариант:
CODE (SQL):
скопировать код в буфер обмена
  1. SELECT t1.id, t2.id, t3.id, ....
  2. FROM tbl t1
  3. LEFT JOIN tbl t2 ON t2.id = t1.parent_id
  4. LEFT JOIN tbl t3 ON t3.id = t2.parent_id
  5. LEFT JOIN tbl t4 ON t4.id = t3.parent_id
  6. ....

Столько раз, сколько достаточно, чтоб покрыть максимально предполагаемую вложенность. Ну и проверку, дотянулись ли до корня и, если не дотянулись, то в этом редком случае второй запрос.
8. DlTA - 16 Декабря, 2011 - 19:13:15 - перейти к сообщению
tuareg пишет:
По факту там только один запрос. Но надо знать сколько вложений
чтоб знать количество, его надо откуда то получить даже если это число хранить в той же таблице, это уже как минимум запрос,
зная количество конечно можно сгенерить многоуровневый селект, но интересовал более изящный вариант.
9. Champion - 16 Декабря, 2011 - 19:24:07 - перейти к сообщению
DlTA пишет:
чтоб знать количество, его надо откуда то получить
Можно получить слефтжойнить 50 раз - этого точно достаточно.
Мускуль сам поймет, что пора кончать джойнить, когда очередной join ничего не вернет.

DlTA пишет:
интересовал более изящный вариант.
EuGen пишет:
полный путь (в упорядоченном виде) для каждого элемента в отдельном поле.
10. DlTA - 16 Декабря, 2011 - 19:49:35 - перейти к сообщению
Champion пишет:
SELECT t1.id, t2.id, t3.id, ....
FROM tbl t1
LEFT JOIN tbl t2 ON t2.id = t1.parent_id
LEFT JOIN tbl t3 ON t3.id = t2.parent_id

а это не сильно дофига длинная строка получается?
даже при 50 джоинах получится как минимум 100 ячеек на выходе (ид и название как минимум, и то фигня что почти все null-ом заполнены)
11. Champion - 16 Декабря, 2011 - 19:55:22 - перейти к сообщению
А что такого в том, что она длинная?)
Если набирать лень, то это можно сделать циклом. Если есть опасения, что мускуль такую длинную строку не съест, то нужно попробовать. Должен съесть.
(Добавление)
DlTA пишет:
и то фигня что почти все null-ом заполнены
Это разве делает какую-то проблему?
12. tuareg - 16 Декабря, 2011 - 20:34:46 - перейти к сообщению
На Хабре по-моему чел сделал процедуру рекурсивную.
Я просто не могу понять в чем у Вас проблема, ну допустим будет запрос не один, ну и? его нельзя закэшировать? Если 2 запроса сделайте процедуру+ КЭШ
13. EuGen - 16 Декабря, 2011 - 20:38:33 - перейти к сообщению
И в чем разница? Рекурсивная процедура ничуть не лучше рекурсии на php.

50 JOIN - плохо, если данных действительно много. Изящества здесь уж точно нет.
То, что я предлагал с полным путем - вряд ли изящно тоже, так как в случае перемещения узла где-нибудь в середине пути будет очень много запросов на поиск и обновление (по сути обновить нужно будет все нижележащие поддеревья).

Изящно можно везде почти, кроме MySQL
14. tuareg - 17 Декабря, 2011 - 00:29:03 - перейти к сообщению
Да не ну это глупо, зачем??? MySql не для этого
15. DlTA - 17 Декабря, 2011 - 01:07:24 - перейти к сообщению
tuareg пишет:
Да не ну это глупо, зачем??? MySql не для этого

не для чего?

 

Powered by ExBB FM 1.0 RC1