2013-03-17 12 views
6

Mam dwie tabele: kategorie i elementy. Mam przechowywane kategorie przy użyciu zagnieżdżonej struktury zestawu. Kategorie mają przedmioty. Elementy można dodawać tylko do węzłów liści kategorii głównej.Uzyskaj liczbę elementów związanych z kategorią zagnieżdżoną w sql

Dla np: Kategorie

Vehicles 
    Bikes 
     Bajaj 
    Automobiles 
Art & Antiques 
    Amateur Art 

Przedmioty mogą być dodawane do kategorii Bajaj, samochody i amatorów sztuki w tym przypadku.

Powiedzmy, istnieją 2 pozycji wewnątrz Bajaj, 5 pozycji wewnątrz samochody, 2 wewnątrz Amatorskiej Sztuki

Dla kategoriach poziomu korzeń chcę, aby wyświetlić następujące:

- Vehicles (7 items) 
- Art & Antiques (2 items) 

Jak mogę to zrobić?

Oto zrzut SQL do pracy z kilkoma przykładowymi danymi

-- 
-- Table structure for table `categories` 
-- 

CREATE TABLE IF NOT EXISTS `categories` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`parent_id` int(11) DEFAULT NULL, 
`title` varchar(64) COLLATE utf8_unicode_ci NOT NULL, 
`lft` int(11) NOT NULL, 
`lvl` int(11) NOT NULL, 
`rgt` int(11) NOT NULL, 
`root` int(11) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `IDX_3AF34668727ACA70` (`parent_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=28 ; 

-- 
-- Dumping data for table `categories` 
-- 

INSERT INTO `categories` (`id`, `parent_id`, `title`, `lft`, `lvl`, `rgt`, `root`) VALUES 
(22, NULL, 'Vehicles', 1, 0, 8, 22), 
(23, 22, 'Bikes', 2, 1, 5, 22), 
(24, 23, 'Bajaj', 3, 2, 4, 22), 
(25, 22, 'Automobiles', 6, 1, 7, 22), 
(26, NULL, 'Art & Antiques', 1, 0, 4, 26), 
(27, 26, 'Amateur Art', 2, 1, 3, 26); 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `items` 
-- 

CREATE TABLE IF NOT EXISTS `items` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`category_id` int(11) NOT NULL, 
`title` varchar(100) NOT NULL, 
PRIMARY KEY (`id`), 
KEY `FK_403EA91BA33E2D84` (`category_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; 

-- 
-- Dumping data for table `items` 
-- 

INSERT INTO `items` (`id`, `category_id`, `title`) VALUES 
(1, 24, 'Pulsor 150 cc'), 
(2, 24, 'Discover 125 cc'), 
(3, 27, 'Art of dream'), 
(4, 25, 'Toyota Car'); 

-- 
-- Constraints for dumped tables 
-- 

-- 
-- Constraints for table `categories` 
-- 
ALTER TABLE `categories` 
ADD CONSTRAINT `FK_3AF34668727ACA70` FOREIGN KEY (`parent_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL; 

-- 
-- Constraints for table `items` 
-- 
ALTER TABLE `items` 
ADD CONSTRAINT `FK_403EA91BA33E2D84` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE; 

węzły korzeniowe mają NULL w dziedzinie parent_id

Aktualizacja:

udało mi się sprowadzić do korzeni z wykorzystaniem tego zapytanie:

SELECT c.id,c.title,cte.co FROM categories c 
JOIN 
(SELECT 
    c0_.id,c0_.root,COUNT(i.id) co 
    FROM 
    categories c0_ 
    JOIN items i ON c0_.id=i.category_id 
    WHERE c0_.rgt = 1 + c0_.lft 
    GROUP BY c0_.id 
) cte 
ON cte.root=c.id 
WHERE c.parent_id is null 

Powyższe zapytanie dotyczy kategorii poziomu głównego. Teraz, gdy użytkownik kliknie na kategorię poziomu root, chcę zrobić to samo.

dla np gdy ktoś kliknie na pojazdach powinny uzyskać:

Bikes (2) 
Automobiles (5) 

Do tego próbowałem:

SELECT c.id,c.title,cte.co FROM categories c 
JOIN 
(SELECT 
    c0_.id,c0_.root,COUNT(i.id) co 
    FROM 
    categories c0_ 
    JOIN items i ON c0_.id=i.category_id 
    WHERE 
    c0_.rgt = 1 + c0_.lft 
    GROUP BY c0_.id 
) cte 
ON cte.root=c.id 
WHERE c.parent_id=1 

Ten wrócił pusty zestaw wyników. co jest nie tak w tym zapytaniu?

+1

zobaczyć zagnieżdżony zestaw części tego artykułu http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/ – Sebas

Odpowiedz

2
SELECT parent.title, 
(SELECT count(i.id) count FROM items i 
WHERE category_id IN 
(
SELECT child.id FROM categories child WHERE child.lft>=parent.lft AND 
    child.rgt<=parent.rgt AND child.root=parent.root 
) 
) 
FROM categories parent 
WHERE [email protected]_id; 

proszę o poinformowanie mnie, jeśli to nie zadziała

0

Coś takiego powinno działać.

select c1.title, count(*) itemcount 
from categories c1 join categories c2 
on c2.parent_id = c1.id 
join items on items.category_id = c2.id 
group by c1.title 
+0

to dostanie się tylko do se poziom kondycji. – Ambrose

+0

to zapytanie zwraca także kategorię Rower, która znajduje się w kategorii pojazdów. – sonam

1

Jak o coś takiego:

SELECT COUNT(items.id), 
    (SELECT lookup.title 
    FROM categories lookup 
    WHERE lookup.id = categories.root) 
FROM items, categories 
WHERE categories.id = items.category_id 
GROUP BY categories.root; 

oparty na wejściu z powyższego skryptu daje mi:

3 | Vehicles 
1 | Art & Antiques 

aby wybrać dla danego korzenia dodać

AND categories.root = @id 

gdzie @id jest twoim root ID yo szukasz.

Alternatywnie, jeśli chcesz wybrać nazwą korzenia zrobić coś (straszny) tak:

SELECT title, total 
    FROM 
    (SELECT COUNT(items.id) total, 
      (SELECT lookup.title 
     FROM categories lookup 
     WHERE lookup.id = categories.root) title 
    FROM items, categories 
    WHERE categories.id = items.category_id 
    GROUP BY categories.root; 
    ) AS some_table 
WHERE some_table.title = @root_name 

gdzie @root_name to nazwa węzła głównego (w cudzysłowie oczywiście)

+0

Tak, daje to poprawny wynik powyżej. W jaki sposób mogę uzyskać dany węzeł główny, np. Tylko pojazdy? – sonam

+0

Jeśli znasz identyfikator węzła głównego, po prostu dodaj "WHERE categories.root = " do zewnętrznego wyboru (przed grupą przez)? Chyba, że ​​chcesz wybrać według tytułu? –

+0

Edytowałem odpowiedź dla obu opcji –

Powiązane problemy