Witam.

Mam do zrealizowania następujący problem:
wyciągnąć cenę kategorii z drzewa. Jeżeli kategoria ma przypisaną cenę - zwracamy ją, jeżeli nie ma (NULL), a ma przypisanego rodzica (NOT NULL), ściągamy cenę z rodzica. Jeżeli ten nie ma, pyta dziadka, itd, dopóki trafimy na cenę lub kategorię, która nie ma już rodzica.

Struktura danych:
  1. CREATE TABLE `cms_announcements_categories` (
  2. `category_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `category_title` text NOT NULL,
  4. `category_parent` int(11) UNSIGNED DEFAULT NULL,
  5. `category_data_price` float(6,2) DEFAULT NULL,
  6. PRIMARY KEY (`category_id`),
  7. KEY `category_parent` (`category_parent`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
  9.  
  10. ALTER TABLE `cms_announcements_categories`
  11. ADD CONSTRAINT `cms_announcements_categories_ibfk_1` FOREIGN KEY (`category_parent`) REFERENCES `cms_announcements_categories` (`category_id`) ON DELETE CASCADE;


Próbowałem rozwiązać to w następujący sposób:
  1. DROP FUNCTION IF EXISTS AnnouncementsCategoriesGetPrice;
  2.  
  3. DELIMITER //
  4.  
  5. CREATE FUNCTION AnnouncementsCategoriesGetPrice(iCategoryId INT(11)) RETURNS float(6,2)
  6. BEGIN
  7. DECLARE iResult float(6,2);
  8.  
  9. SELECT (
  10. CASE
  11. WHEN category_data_price IS NOT NULL THEN category_data_price
  12. ELSE(
  13. CASE
  14. WHEN category_parent IS NOT NULL THEN AnnouncementsCategoriesGetPrice(category_parent)
  15. ELSE NULL
  16. END)
  17. END
  18. ) INTO iResult FROM cms_announcements_categories WHERE category_id = iCategoryId;
  19.  
  20. RETURN iResult;
  21. END//
  22.  
  23. DELIMITER ;
  24.  
  25. SELECT AnnouncementsCategoriesGetPrice(10);


Niestety, funkcje nie mogą być rekurencyjne.

Ugryzłem to od strony procedur, ale nie potrafię sobie z tym poradzić:
  1. DROP PROCEDURE IF EXISTS AnnouncementsCategoriesGetPrice;
  2.  
  3. DELIMITER //
  4.  
  5. CREATE PROCEDURE AnnouncementsCategoriesGetPrice(IN iCategoryId INT(11), OUT iResult float(6,2))
  6. BEGIN
  7. DECLARE iResult float(6,2);
  8.  
  9. SELECT category_data_price INTO iResult FROM cms_announcements_categories WHERE category_id = iCategoryId;
  10.  
  11. IF (iResult IS NULL AND category_parent) THEN
  12. CALL AnnouncementsCategoriesGetPrice(category_parent, iResult);
  13. END IF;
  14. END//
  15.  
  16. DELIMITER ;
  17.  
  18. CALL AnnouncementsCategoriesGetPrice(10, @result);
  19. SELECT @result;


Jakby ktoś zechciał mi pomóc i pochylić się nad problemem, byłbym wdzięczny.

Pozdrawiam serdecznie,
Athlan.




EDIT: zrobiłem:

  1. CREATE FUNCTION AnnouncementsCategoriesGetPrice(iCategoryId int(11)) RETURNS float(6,2)
  2. BEGIN
  3. DECLARE iResult FLOAT(6,2);
  4. DECLARE iPointer INT(11);
  5.  
  6. SET iPointer = iCategoryId;
  7. SET iResult = NULL;
  8.  
  9. WHILE (iPointer IS NOT NULL AND iPointer IS NOT NULL) DO
  10. SET iResult = (SELECT category_data_price FROM cms_announcements_categories WHERE category_id = iPointer);
  11. SET iPointer = (SELECT category_parent FROM cms_announcements_categories WHERE category_id = iPointer);
  12. END WHILE;
  13.  
  14. RETURN iResult;
  15. END