Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Rekurencja w proceduerze składowanej
Forum PHP.pl > Forum > Bazy danych > MySQL
phpion
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:
  1. CREATE TABLE IF NOT EXISTS `category` (
  2. `id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
  3. `parent_id` INT UNSIGNED NULL DEFAULT NULL ,
  4. `name` VARCHAR(45) NOT NULL ,
  5. `cards` INT UNSIGNED NOT NULL DEFAULT 0 ,
  6. PRIMARY KEY (`id`) ,
  7. INDEX fk_category_category (`parent_id` ASC) ,
  8. CONSTRAINT `fk_category_category`
  9. FOREIGN KEY (`parent_id` )
  10. REFERENCES `category` (`id` ) ON DELETE CASCADE ON UPDATE NO ACTION)
  11. ENGINE = InnoDB;
  12.  
  13. CREATE TABLE IF NOT EXISTS `card` (
  14. `id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
  15. `name` VARCHAR(45) NOT NULL ,
  16. PRIMARY KEY (`id`) )
  17. ENGINE = InnoDB;
  18.  
  19. CREATE TABLE IF NOT EXISTS `card_category` (
  20. `category_id` INT UNSIGNED NOT NULL ,
  21. `card_id` INT UNSIGNED NOT NULL ,
  22. INDEX fk_card_category_category (`category_id` ASC) ,
  23. INDEX fk_card_category_card (`card_id` ASC) ,
  24. PRIMARY KEY (`category_id`, `card_id`) ,
  25. CONSTRAINT `fk_card_category_category`
  26. FOREIGN KEY (`category_id` )
  27. REFERENCES `category` (`id` ) ON DELETE CASCADE ON UPDATE NO ACTION,
  28. CONSTRAINT `fk_card_category_card`
  29. FOREIGN KEY (`card_id` )
  30. REFERENCES `card` (`id` ) ON DELETE CASCADE ON UPDATE NO ACTION)
  31. ENGINE = InnoDB;

czyli w zasadzie standardzik. Napisałem procedurę, która ma obsługiwać aktualizację pola `cards` w tabeli `category`:
  1. DROP PROCEDURE IF EXISTS update_category_items;
  2.  
  3. DELIMITER |
  4. CREATE PROCEDURE update_category_items (p_category_id INT)
  5. BEGIN DECLARE l_parent_id INT DEFAULT NULL;
  6.  
  7. UPDATE category SET cards=(SELECT COUNT(*) FROM card_category WHERE category_id=p_category_id LIMIT 1 ) WHERE id=p_category_id LIMIT 1 ;
  8.  
  9. SELECT parent_id INTO l_parent_id FROM category WHERE id=p_category_id LIMIT 1 ;
  10.  
  11. IF l_parent_id != NULL THEN
  12. CALL update_category_items(l_parent_id);
  13. END IF;
  14. END|
  15. 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.:
  1. 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:
  1. 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:
  1. DROP PROCEDURE IF EXISTS update_category_items;
  2.  
  3. DELIMITER |
  4. CREATE PROCEDURE update_category_items (p_category_id INT)
  5. BEGIN DECLARE l_parent_id INT;
  6.  
  7. UPDATE category SET cards=(SELECT COUNT(*) FROM card_category WHERE category_id=p_category_id LIMIT 1 ) WHERE id=p_category_id LIMIT 1 ;
  8.  
  9. SELECT IFNULL(parent_id, 0) INTO l_parent_id FROM category WHERE id=p_category_id LIMIT 1 ;
  10.  
  11. IF l_parent_id > 0 THEN
  12. CALL update_category_items(l_parent_id);
  13. END IF;
  14. END|
  15. DELIMITER ;
dr_bonzo
Do NULLi nie uzywasz zwyklych operatorow, bo zawsze zwracaja ci false.
Ale jak to zapisac - nie wiem, nie bawilem sie procedurami.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.