J'ai du mal à élaborer la documentation PostgreSQL pour les requêtes récursives et je me demande si quelqu'un pourrait être en mesure de proposer une suggestion pour ce qui suit.
Voici les données:
parent_id 1 -> children 3, 4, 5, 6, 7, 8 parent_id 2 -> children 3 child_id 3 -> parents 1, 2 child_id 4 -> parents 1 child_id 7 -> parents 6, 5, 4, 1
3 Réponses :
Pour obtenir tous les enfants du sujet 1, vous pouvez utiliser
WITH RECURSIVE c AS (
SELECT 1 AS id
UNION ALL
SELECT sa.child_id
FROM subject_associations AS sa
JOIN c ON c.id = sa. parent_id
)
SELECT id FROM c;
Cela semble fonctionner très bien - également en sens inverse. Un peu plus simple que je ne le pensais (j'ai continué à essayer de me joindre sur des sujets).
Vous vous joindriez avec sujets dans la requête externe.
CREATE OR REPLACE FUNCTION func_finddescendants(start_id integer)
RETURNS SETOF subject_associations
AS $$
DECLARE
BEGIN
RETURN QUERY
WITH RECURSIVE t
AS
(
SELECT *
FROM subject_associations sa
WHERE sa.id = start_id
UNION ALL
SELECT next.*
FROM t prev
JOIN subject_associations next ON (next.parentid = prev.id)
)
SELECT * FROM t;
END;
$$ LANGUAGE PLPGSQL;
Merci pour cette réponse. J'ai trouvé l'autre un peu plus facile à comprendre - je ne suis pas tout à fait sûr du fonctionnement de next / prev.
Vous êtes les bienvenus. prev est ce qui est actuellement dans votre table récursive, t dans ce cas. next est ce que vous allez ajouter à la table récursive après une jointure réussie. C'est très similaire à la réponse de Laurenz, je viens de donner à la table récursive un alias dans ma deuxième instruction select. Dans ma réponse, t est exactement comme c dans la réponse de Laurenz. Il fait simplement la jointure dans l'ordre inverse. J'ai sélectionné dans la table récursive puis rejoint la table subject_associations.
Merci encore. Pour le moment, je pense que je préfère utiliser l'autre réponse, qui semble bien fonctionner dans mon application, alors j'espère que cela ne vous dérange pas que je marque cela comme accepté.
Essayez ceci
--- Table
-- DROP SEQUENCE public.data_id_seq;
CREATE SEQUENCE "data_id_seq"
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
ALTER TABLE public.data_id_seq
OWNER TO postgres;
CREATE TABLE public.data
(
id integer NOT NULL DEFAULT nextval('data_id_seq'::regclass),
name character varying(50) NOT NULL,
label character varying(50) NOT NULL,
parent_id integer NOT NULL,
CONSTRAINT data_pkey PRIMARY KEY (id),
CONSTRAINT data_name_parent_id_unique UNIQUE (name, parent_id)
)
WITH (
OIDS=FALSE
);
INSERT INTO public.data(id, name, label, parent_id) VALUES (1,'animal','Animal',0);
INSERT INTO public.data(id, name, label, parent_id) VALUES (5,'birds','Birds',1);
INSERT INTO public.data(id, name, label, parent_id) VALUES (6,'fish','Fish',1);
INSERT INTO public.data(id, name, label, parent_id) VALUES (7,'parrot','Parrot',5);
INSERT INTO public.data(id, name, label, parent_id) VALUES (8,'barb','Barb',6);
--- Function
CREATE OR REPLACE FUNCTION public.get_all_children_of_parent(use_parent integer) RETURNS integer[] AS
$BODY$
DECLARE
process_parents INT4[] := ARRAY[ use_parent ];
children INT4[] := '{}';
new_children INT4[];
BEGIN
WHILE ( array_upper( process_parents, 1 ) IS NOT NULL ) LOOP
new_children := ARRAY( SELECT id FROM data WHERE parent_id = ANY( process_parents ) AND id <> ALL( children ) );
children := children || new_children;
process_parents := new_children;
END LOOP;
RETURN children;
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
ALTER FUNCTION public.get_all_children_of_parent(integer) OWNER TO postgres
--- Test
SELECT * FROM data WHERE id = any(get_all_children_of_parent(1))
SELECT * FROM data WHERE id = any(get_all_children_of_parent(5))
SELECT * FROM data WHERE id = any(get_all_children_of_parent(6))
Vous pouvez commencer par n'importe quel sujet. Je suppose que je ne comprends pas entièrement votre question.
En effet. Donc si je commençais avec le sujet 1, quelle requête SQL me donnerait tous les enfants, et si avec le sujet 7, quelle requête donnerait à tous les parents? Etc.