Вы можете использовать дизайн Materialized Path . Путь к каталогу является примером материализованного пути. То есть ряд значений предков, соединенных вместе, с некоторыми символами ("/" или "," являются общими), разделяющими их.
Так что вы можете иметь категории:
+---------------------------------------------+
| cat_id | Name | cat_path | depth |
+---------------------------------------------+
| 1 | Electronics | 1/ | 1 |
| 2 | Digital cameras | 1/2/ | 2 |
| 3 | SLR cameras | 1/2/3/ | 3 |
| 4 | Audio | 1/4/ | 2 |
| 5 | Speakers | 1/4/5/ | 3 |
| 6 | Wall Satellites | 1/4/5/6/ | 4 |
| 7 | Computers | 1/7/ | 2 |
+---------------------------------------------+
Теперь, если вы хотите, чтобы все продукты, которые находятся в Аудио, вы можете сделать запрос, например:
SELECT p.*, pc.*
FROM Products p JOIN Categories pc ON (p.cat_id = pc.cat_id)
JOIN Categories c ON (pc.cat_path LIKE c.cat_path||'%')
WHERE c.name = 'Audio';
Например, '1/4/5/6' LIKE '1/4/%'
- правда, поэтому настенные спутники включены. И то же самое для любой другой подкатегории Аудио.
Ваш вопрос о рендеринге меню: я полагаю, вы хотите, чтобы меню отображалось:
- Все предки выбранной категории
- Все братья и сестры предков выбранной категории
Поэтому, если вы выберете «Динамики», вы увидите:
- Электроника
- Аудио
- Компьютеры
- Цифровые фотоаппараты
Но вам не нужны потомки компьютеров или цифровых камер (то есть «двоюродные братья» ораторов).
SELECT uncle.name, uncle.depth
FROM Categories chosen
JOIN Categories ancestor ON (chosen.cat_path LIKE ancestor.cat_path||'%')
JOIN Categories uncle ON (ancestor.depth = uncle.depth
AND SUBSTRING(REVERSE(ancestor.cat_path), 3, 100) = SUBSTRING(REVERSE(uncle.cat_path), 3, 100))
WHERE chosen.name = 'Speakers'
ORDER BY uncle.depth, uncle.name;
Я использую трюк, чтобы обнаружить дядюшек: сравнивать пути после удаления последнего элемента. Чтобы сделать это, переверните строку и затем удалите элемент first . Это должно работать, по крайней мере, в MySQL и MS SQL Server, но REVERSE()
не является стандартным и может не переноситься на другие марки СУБД.
Обратите внимание, что вам, вероятно, следует указать более одной цифры для каждого элемента в cat_path
, и в этом случае смещение подстроки также должно увеличиться.