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 ;