Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MySQL > Древовидная структура для страниц


Автор: GZep 26.10.2010, 09:26
Здравствуйте!

Есть веб-приложение с таким вариантом наименовая страниц:
Код

index
blog.index
projects.index
projects.myproject.index
projects.myproject.edit

То есть используется точечная нотация.
Так же установлено, что индекс файл в каталоге - index. То есть projects. == projects.index
Для выборки использую такой запрос:
Код

SELECT * FROM `pages` WHERE `name` = 'projects.myproject.edit' LIMIT 1

Хотелось бы узнать как при такий структуре (когда нету поля `parent_name`) вложить в запрос выборку поля `title` из родительский страниц?
Впринципе, могу до запроса уже скриптом составить список радительских страниц, расспарсив projects.myproject.edit. То есть оплучится:
Код

Исходная страница: projects.myproject.edit
Папа: projects.myproject.index
Дедушка: projects.index
Прадедушка: index

Буду рад любой помощи.
P.S. хотелось бы все таки без id и parent_id обходится...

Автор: skyboy 26.10.2010, 10:01
вопрос в том, как средствами SQL вырезать из строки последнюю точку и следующие за ней символы?

Автор: Akina 26.10.2010, 10:22
Цитата(skyboy @  26.10.2010,  11:01 Найти цитируемый пост)
как средствами SQL вырезать из строки последнюю точку и следующие за ней символы? 

Наиболее разумно создать пользовательскую функцию, выполняющую требуемое.

Автор: GZep 26.10.2010, 15:38
Цитата(skyboy @  26.10.2010,  10:01 Найти цитируемый пост)
вопрос в том, как средствами SQL вырезать из строки последнюю точку и следующие за ней символы? 

ненене... потому что:
Цитата(GZep @  26.10.2010,  09:26 Найти цитируемый пост)
могу до запроса уже скриптом составить список радительских страниц, расспарсив projects.myproject.edit

в общем, видимо, раз дело зашло о функции - так и предется делать. Ну да, это самый простой способ, самый быстрый и лежит на поверхности.

Тогда, подскажите пожалуйста: я в join не силен вообще никак, помогите составить запрос.
Нужно к этому запросу:
Код

SELECT * FROM `pages` WHERE `name` = 'projects.myproject.edit' LIMIT 1

добавить второй запрос - выборку имен и тайтлов у родительских страниц:
Код

SELECT `name`, `title`  WHERE
`name` = 'projects.myproject.index' OR
`name` = 'projects.index' OR
`name` = 'index'

то есть объединить эти запросы. У родительский записей нужно грузить только `name` и `title`.
Если не затруднит, конечно. Сам пробовал через phpMyAdmin делать JOIN-выборку, да только не вышло - не научился пока, опыта мало.

Автор: skyboy 26.10.2010, 21:42
Цитата(GZep @  26.10.2010,  14:38 Найти цитируемый пост)
У родительский записей нужно грузить только `name` и `title`.

Цитата(GZep @  26.10.2010,  14:38 Найти цитируемый пост)
SELECT *

union позволяет объединить в один запрос только запросы с одинаковым количеством полей в результате.
Код

select *
from `pages`
where 'projects.myproject.edit' like concat(`name`, "%")
order by length(`name`)

Автор: GZep 26.10.2010, 23:27
Цитата(skyboy @  26.10.2010,  21:42 Найти цитируемый пост)
union позволяет объединить в один запрос только запросы с одинаковым количеством полей в результате.

спасибо. видимо, непонимание этого и было причиной неудавшихся попыток выборки.
Цитата(skyboy @  26.10.2010,  21:42 Найти цитируемый пост)
where 'projects.myproject.edit' like concat(`name`, "%")

на ваш запрос выбралась только исходная страница без родителей.

Быть может тогда выбирать так:
Код

SELECT *
FROM `pages`
WHERE `name` = 'projects.myproject.edit'
OR `name` = 'projects.myproject.index'
OR `name` = 'projects.index'
OR `name` = 'index'
ORDER BY LENGTH( `name` ) DESC
LIMIT 0 , 30

Или это можно оптимизировать?

Автор: skyboy 27.10.2010, 10:14
Цитата(GZep @  26.10.2010,  22:27 Найти цитируемый пост)
на ваш запрос выбралась только исходная страница без родителей.

не понимаю. может, я неверно понял условия?
вот тестовая таблица:
Код

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `str` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
)
INSERT INTO `test` (`id`, `str`) VALUES
(1, 'projects.myproject.edit'),
(2, 'projects.myproject'),
(3, 'projects'),
(4, 'projects.myproject.save'),
(5, 'projects.secondproject'),
(6, 'database');

даже некорректный изначальный запрос
Код

SELECT *
FROM `test`
WHERE 'projects.myproject.edit' LIKE concat( str, "%" )

возвращает на текущих данных только три записи:
Цитата

3   projects
2   projects.myproject
1   projects.myproject.edit

некорректный запрос потому, что если была бы запись "projects.myproject.editandsave", она бы тоже вывелась. корректный вариант будет:
Код

SELECT *
FROM `test`
WHERE 'projects.myproject.edit' LIKE concat(str, ".", "%") OR str = 'projects.myproject.edit'
ORDER BY length( str )

и это уже нормально и предсказуемо работает.

Добавлено через 2 минуты и 58 секунд
опс, сорри.
я, видать, не вчитался.
мое решение для "канонiческого" materialized path. а тут нечто не совсем обычное.
ща придумаю.

Добавлено через 8 минут и 3 секунды
".index" только в конце?
Код

SELECT *
FROM `test`
WHERE 'projects.myproject.edit' LIKE concat(replace(str, ".index", ""), ".", "%") 
       OR str = 'projects.myproject.edit' 
       OR str = "index"
ORDER BY length( str )

Автор: GZep 27.10.2010, 13:43
skyboy, спасибо большое, последний вариант практически исчерпывающий, но есть проблема с этим .index на конце: (ваша структура)
Код

INSERT INTO `test` (`id`, `str`) VALUES
(1, 'projects.myproject.edit'),
(2, 'projects.myproject'),
(3, 'projects'),
(4, 'projects.myproject.save'),
(5, 'projects.secondproject'),
(6, 'database');

Практически идеал, только projects.myproject.edit должен выбираться крайним, как исходная страница, но ORDER BY length( str ) предпологает сортировку по длинне, а тот же projects.myproject.index длинее. (видимо, .index на конце - плохая идея)
Наверное, я уже надоел, но немогли бы вы предложить для такого:
Код

INSERT INTO `test` (`id`, `str`) VALUES
(1, 'index'),
(2, 'projects.myproject.edit'),
(3, 'projects.myproject.'),
(4, 'projects.'),
/* projects (без точки на конце доставать не надо) */
(5, 'projects'),
(6, 'projects.myproject.save'),
(7, 'projects.secondproject'),
(8, 'database');

чтобы на выходе было:
Код

projects.myproject.edit
projects.myproject.
projects.
index

позже подытожу - может кому-нибудь будет полезным.

Автор: skyboy 27.10.2010, 13:49
Цитата(GZep @  27.10.2010,  12:43 Найти цитируемый пост)
но ORDER BY length( str ) предпологает сортировку по длинне

угу. тогда мучительное при большой вложенности order by length(replace(str, ".index", "")) smile

Добавлено через 3 минуты и 1 секунду
Цитата(GZep @  27.10.2010,  12:43 Найти цитируемый пост)
но немогли бы вы предложить для такого:

а куда тут уже .index делся?

Автор: GZep 27.10.2010, 16:59
skyboy, ааа... всё! это победа smile не думал, что SQL позволяет делать ТАКОЕ даже в сортировке:
Цитата(skyboy @  27.10.2010,  13:49 Найти цитируемый пост)
 order by length(replace(str, ".index", ""))

Цитата(skyboy @  27.10.2010,  13:49 Найти цитируемый пост)
а куда тут уже .index делся? 

а все, не нужно, order by length(replace(str, ".index", "")) решил все проблемы : )

Автор: skyboy 27.10.2010, 18:26
два ограничения: по скорости работы(большое количество записей - невозможность использовать ключи из-за использования функции - большее время выполнения) и .index должно быть только в хвосту. ".indexStage" и прочие ".index*" не допускаются

Автор: GZep 5.11.2010, 00:16
Цитата(skyboy @  27.10.2010,  18:26 Найти цитируемый пост)
.index должно быть только в хвосту. ".indexStage" и прочие ".index*" не допускаются 

почему же?
Цитата(skyboy @  27.10.2010,  13:49 Найти цитируемый пост)
order by length(replace(str, ".index", "")

всё правильно, только если такая структура:
Код

index
dir.index
subdir.index
...

dir.index будет изменяться на dir и при выборке будет первее index. Решается так:
Код

/* отсукаем index, БЕЗ точки в начале */
order by length(replace(str, "index", "")

сначало подумал, что такой подход даст проблемы в такой структуре:
Код

index
dir.indexfile.index
somthing.myindex
и т.п.

но проблем не возникло, потому что подстрока index вырезается из всех значений для установки сортировки. За счет того, что подстрока вырезается у всех - проблем и не возникает.

Автор: skyboy 5.11.2010, 14:12
блин, чувствую себя извращенцем.
у тебя пробела быть не может, верно?
тогда вырезай ".index" из concat(str, " ") - это даст уверенность, что .index будет вырезаться только из хвоста.

Автор: GZep 7.11.2010, 12:50
ок. пасибо : ) тема, видимо, раскрыта полностью, и исчерпала себя...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)