написание SQL-запроса с вложенными наборами - PullRequest
0 голосов
/ 27 февраля 2012

Мне нужно написать запрос для выполнения поиска, в котором все результаты сопоставляются по категориям.
У категорий есть подкатегории, и они работают как модель вложенного набора, и у каждой есть столбцы lft и rgt.

Если cat2, cat3 и cat4 являются дочерними элементами cat1, тогда их значения .lft равны между cat1.lft и cat1.rgt

allкатегории хранятся в таблице CATEGORIES и имеют ID в качестве первичного ключа.

мне нужно получить категорию ID найти все элементы таблицы ITEMS, которые относятся к этой категории, но такжевсе элементы, которые относятся к подкатегориям категорий.

запрос, который я ищу, будет выглядеть примерно так:

 SELECT i.id, i.name
 FROM items AS i, categories AS c
 WHERE i.category_lft BETWEEN c.given_cat_id_lft AND c.given_cat_id_rgt

что я имею в виду, я получаю первичный ключ категории (ID), нопо запросу мне нужно работать с их значениями rgt и ltf

Должен ли я использовать подзапросы или, возможно, объединения?И каким должен быть запрос?У меня действительно нет такого опыта в SQL.

Ответы [ 3 ]

1 голос
/ 27 февраля 2012
 SELECT i.id
      , i.name
 FROM items AS i
   JOIN categories AS c
     ON i.category_id = c.id
   JOIN categories AS myc
     ON c.category_lft BETWEEN myc.lft AND myc.rgt
 WHERE myc.id = @GivenCategoryID
0 голосов
/ 27 февраля 2012

Попробуйте это:

CREATE table #Category(
id      INT NOT NULL,
name    VARCHAR(20) NOT NULL,
parentid    INT NOT NULL
)

INSERT INTO #Category (id, name, parentid) VALUES
(1, 'parts', 1),
(2, 'processor', 1),
(3, 'AMD', 2),
(4, 'Intel', 2),
(5, 'Hard Disk', 1),
(6, 'Memory', 1),
(7, 'DDR1', 6),
(8, 'DDR2', 6),
(9, 'DDR3', 6),
(10, '533Mhz', 7),
(11, '667Mhz', 8),
(12, '800Mhz', 8)

CREATE table #Items(
id      INT NOT NULL,
name    VARCHAR(20) NOT NULL,
categoryId  INT NOT NULL
)

INSERT INTO #Items (id, name, categoryId) VALUES
(1, 'AMD Phenom', 3),
(2, 'AMD Sempron', 3),
(3, 'AMD Athlon', 3),
(4, 'Intel core 2 duo', 4),
(5, 'Intel core i3', 4),
(6, 'DDR2 1GB 6667Mhz', 11),
(7, 'Intel 8080', 4),
(8, 'Intel 80286', 4),
(9, 'Intel 80386', 4),
(10, 'Intel 80486', 4),
(11, 'Intel Pentuim', 4),
(12, 'Intel Pentium I', 4)


DECLARE @TopLevelId INT; -- top level category Id
SET @TopLevelId = 2;   -- top level category = AMD processors

WITH CTE AS
(SELECT id, name, parentid, id as Adam, 1 as level
FROM #Category
WHERE id = @TopLevelId
UNION ALL
SELECT #Category.id, #Category.name, #Category.parentid, CTE.Adam, CTE.level + 1
FROM #Category 
INNER JOIN CTE ON
    #Category.parentid = CTE.id
WHERE #Category.id <> @TopLevelId
)
SELECT CTE.id CategoryId, CTE.name as Category, #Items.name as Item
FROM CTE
INNER JOIN #Items ON
    CTE.id = #Items.categoryId
ORDER BY level, CTE.id


DROP table #Category
DROP table #Items
0 голосов
/ 27 февраля 2012

Вам понадобится рекурсивный SQL для решения этой проблемы.

Сначала найдите все подкатегории, которые имеют данную категорию как родитель, дедушка, бабушка и дедушка, ... (не забудьте включить данную категорию сама).

Затем СОЕДИНИТЕ эти подкатегории с категориями в вашей таблице товаров.

Я бы забыл о значениях lft и rght.Это будет адская работа, чтобы сделать эту работу.(как будет работать МЕЖДУ? Основываясь на значениях идентификаторов? Можете ли вы представить себе последствия вставки подкатегории где-то между существующими подкатегориями?)

...