Witam,
mam struktruę tabeli:
p_category: id, parent_id, name
czyli w zasadzie standardzik. Chciałbym napisać funkcję, która zwróci mi ścieżkę od danej kategorii do korzenia. Mam coś takiego:
CREATE OR REPLACE FUNCTION f_get_category_path(category_id integer, shop_id integer) RETURNS p_category AS $BODY$DECLARE r p_category%ROWTYPE; BEGIN SELECT * INTO r FROM p_category WHERE id=$1; IF (r.parent_id > 0) THEN -- SELECT * FROM f_get_category_path(r.parent_id, $2); END IF; RETURN r; END;$BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100;
Jak dobrze pamiętam, to PG nie lubi jak mus się wstawia SQL z parametrami... spróbuj coś w tym stylu:
EXECUTE 'SELECT * FROM f_get_category_path('||r.parent_id||', '||$2||');'
Dzięki za odpowiedź. Teraz ciało funkcji wygląda w ten sposób:
DECLARE r p_category%ROWTYPE; BEGIN SELECT * INTO r FROM p_category WHERE id=$1; IF (r.parent_id IS NOT NULL AND r.parent_id > 0) THEN EXECUTE 'SELECT * FROM f_get_category_path('||r.parent_id||', '||$2||');'; END IF; RETURN r; END;
SELECT * FROM f_get_category_path(7, 1);
Może nie za piękne... Ważne w deklaracji "SETOF "
CREATE OR REPLACE FUNCTION f_get_category_path(category_id integer, shop_id integer) RETURNS SETOF p_category AS $BODY$ DECLARE r p_category%ROWTYPE; aid integer; BEGIN IF category_id IS NULL THEN RETURN; END IF; aid := category_id; LOOP FOR r IN SELECT * FROM p_category WHERE id = aid LOOP RETURN NEXT r; END LOOP; EXIT WHEN NOT r.parent_id > 0; -- Nie wiem czy masz null, czy może błędnie 0 w tym polu jak nie ma rodzica. aid := r.parent_id; END LOOP; RETURN; END; $BODY$ LANGUAGE 'plpgsql' VOLATILE;
Działa wyśmienicie. Musiałem poprawić tylko jedną linijkę:
FOR r IN SELECT * FROM p_category WHERE id = aid
Ja zazwyczaj miałem las, Ty chcesz mieć drzewo, to już nie nazwę błędem Po prostu inna koncepcja (a mi się przypomniało jak było w bazie -1 jak nie było powiązania... i tylko dla tego wspomniałem)
Ciągle mam wrażenie że da się to lepiej napisać, ale bym musiał się tym pobawić, do tej pory nie miałem potrzeby robienia takich funkcji.
Odświeżam temat: mam problem z modyfikacją wyżej podanego rozwiązania. Aktualnie mam tabele:
category: id, parent_id, position
locale: id, code
category_i18n: category_id, locale_id, name
i próbuję pobrać ścieżkę kategorii czyli np. Podkategoria -> Kategoria. Stworzyłem widok:
CREATE OR REPLACE VIEW shp_view_category AS SELECT a.category_id, b.parent_id, a.name, c.code AS locale_code FROM shp_category_i18n a LEFT JOIN shp_category b ON b.id = a.category_id LEFT JOIN shp_locale c ON c.id = a.locale_id;
CREATE OR REPLACE FUNCTION f_get_category_path(category_id integer, locale character varying) RETURNS SETOF shp_view_category AS $BODY$DECLARE r shp_view_category%ROWTYPE; aid integer; BEGIN IF $2 IS NULL THEN RETURN; END IF; aid := $2; LOOP FOR r IN SELECT * FROM shp_view_category WHERE category_id=aid AND locale_code=$2 LOOP RETURN NEXT r; END LOOP; EXIT WHEN r.parent_id=0 OR r.parent_id IS NULL; aid := r.parent_id; END LOOP; RETURN; END;$BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100 ROWS 1000;
SELECT * FROM f_get_category_path(12, 'pl_PL');
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)