Witam,
chcę napisać sobie procedurę aktualizującą ilość produktów w danej kategorii (uwzględniając hierarchię drzewiastą).
Struktura tabel w uproszczeniu wygląda tak:
CREATE TABLE IF NOT EXISTS `category` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`parent_id` INT UNSIGNED NULL DEFAULT NULL ,
`name` VARCHAR(45) NOT NULL ,
`cards` INT UNSIGNED NOT NULL DEFAULT 0 ,
PRIMARY KEY (`id`) ,
INDEX fk_category_category (`parent_id` ASC) ,
CONSTRAINT `fk_category_category`
FOREIGN KEY (`parent_id` )
REFERENCES `category` (`id` ) ON DELETE CASCADE ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `card` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(45) NOT NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `card_category` (
`category_id` INT UNSIGNED NOT NULL ,
`card_id` INT UNSIGNED NOT NULL ,
INDEX fk_card_category_category (`category_id` ASC) ,
INDEX fk_card_category_card (`card_id` ASC) ,
PRIMARY KEY (`category_id`, `card_id`) ,
CONSTRAINT `fk_card_category_category`
FOREIGN KEY (`category_id` )
REFERENCES `category` (`id` ) ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `fk_card_category_card`
FOREIGN KEY (`card_id` )
REFERENCES `card` (`id` ) ON DELETE CASCADE ON UPDATE NO ACTION)
ENGINE = InnoDB;
czyli w zasadzie standardzik. Napisałem procedurę, która ma obsługiwać aktualizację pola `cards` w tabeli `category`:
DROP PROCEDURE IF EXISTS update_category_items;
DELIMITER |
CREATE PROCEDURE update_category_items (p_category_id INT)
BEGIN DECLARE l_parent_id INT DEFAULT NULL;
UPDATE category SET cards=(SELECT COUNT(*) FROM card_category WHERE category_id=p_category_id LIMIT 1 ) WHERE id=p_category_id LIMIT 1 ;
SELECT parent_id INTO l_parent_id FROM category WHERE id=p_category_id LIMIT 1 ;
IF l_parent_id != NULL THEN
CALL update_category_items(l_parent_id);
END IF;
END|
DELIMITER ;
Problem w tym, że nie wywołuje się rekurencja. Możliwe, że po prostu warunek nie jest spełniony (NULL NULLowi nierówny, ale nie wiem jak inaczej zapisać warunek z wykorzystaniem np. NOT NULL).
Wywołując np.:
CALL update_category_items(3);
aktualizowana jest tylko kategoria o `id` = 3. Jest ona podkategorią dla kategorii o `id` = 1, ale tu już aktualizacja nie następuje.
Dodam jeszcze, że:
SELECT @@max_sp_recursion_depth;
pokazuje 255 więc przypuszczam, że problem jest jednak w warunku.
Proszę o pomoc, wskazówkę.
pion
PS:
problem na pewno jest w warunku - jego usunięcie i każdorazowe wywołanie rekurencji aktualizuje pola (no ale są to niepotrzebne wywołania procedury).
// EDIT:
Problem rozwiązałem inaczej: dodałem IFNULL do SELECTa i zmieniłem warunek. Może komuś się przyda:
DROP PROCEDURE IF EXISTS update_category_items;
DELIMITER |
CREATE PROCEDURE update_category_items (p_category_id INT)
BEGIN DECLARE l_parent_id INT;
UPDATE category SET cards=(SELECT COUNT(*) FROM card_category WHERE category_id=p_category_id LIMIT 1 ) WHERE id=p_category_id LIMIT 1 ;
SELECT IFNULL(parent_id, 0) INTO l_parent_id FROM category WHERE id=p_category_id LIMIT 1 ;
IF l_parent_id > 0 THEN
CALL update_category_items(l_parent_id);
END IF;
END|
DELIMITER ;
Ten post edytował phpion 21.06.2008, 09:23:21