J'ai besoin de calculer la profondeur d'un descendant de son ancêtre. Lorsqu'un enregistrement a object_id = parent_id = ancestor_id
, il est considéré comme un nœud racine (l'ancêtre). J'ai essayé de lancer une WITH RECURSIVE
requête avec PostgreSQL 9.4 .
Je ne contrôle pas les données ou les colonnes. Le schéma de données et de table provient d'une source externe. La table ne cesse de croître . À l'heure actuelle, environ 30 000 enregistrements par jour. Tous les nœuds de l'arborescence peuvent être manquants et ils seront extraits d'une source externe à un moment donné. Ils sont généralement extraits dans l' created_at DESC
ordre, mais les données sont extraites avec des tâches d'arrière-plan asynchrones.
Nous avions initialement une solution de code à ce problème, mais ayant maintenant 5M + lignes, cela prend presque 30 minutes pour terminer.
Exemple de définition de table et de données de test:
CREATE TABLE objects (
id serial NOT NULL PRIMARY KEY,
customer_id integer NOT NULL,
object_id integer NOT NULL,
parent_id integer,
ancestor_id integer,
generation integer NOT NULL DEFAULT 0
);
INSERT INTO objects(id, customer_id , object_id, parent_id, ancestor_id, generation)
VALUES (2, 1, 2, 1, 1, -1), --no parent yet
(3, 2, 3, 3, 3, -1), --root node
(4, 2, 4, 3, 3, -1), --depth 1
(5, 2, 5, 4, 3, -1), --depth 2
(6, 2, 6, 5, 3, -1), --depth 3
(7, 1, 7, 7, 7, -1), --root node
(8, 1, 8, 7, 7, -1), --depth 1
(9, 1, 9, 8, 7, -1); --depth 2
Notez que ce object_id
n'est pas unique, mais la combinaison (customer_id, object_id)
est unique.
Exécuter une requête comme celle-ci:
WITH RECURSIVE descendants(id, customer_id, object_id, parent_id, ancestor_id, depth) AS (
SELECT id, customer_id, object_id, parent_id, ancestor_id, 0
FROM objects
WHERE object_id = parent_id
UNION
SELECT o.id, o.customer_id, o.object_id, o.parent_id, o.ancestor_id, d.depth + 1
FROM objects o
INNER JOIN descendants d ON d.parent_id = o.object_id
WHERE
d.id <> o.id
AND
d.customer_id = o.customer_id
) SELECT * FROM descendants d;
Je voudrais que la generation
colonne soit définie comme la profondeur qui a été calculée. Lorsqu'un nouvel enregistrement est ajouté, la colonne de génération est définie sur -1. Il y a des cas où un parent_id
n'a peut - être pas encore été retiré. Si le parent_id
n'existe pas, il doit laisser la colonne de génération définie sur -1.
Les données finales devraient ressembler à:
id | customer_id | object_id | parent_id | ancestor_id | generation
2 1 2 1 1 -1
3 2 3 3 3 0
4 2 4 3 3 1
5 2 5 4 3 2
6 2 6 5 3 3
7 1 7 7 7 0
8 1 8 7 7 1
9 1 9 8 7 2
Le résultat de la requête doit être de mettre à jour la colonne de génération à la profondeur correcte.
J'ai commencé à travailler à partir des réponses à cette question connexe sur SO .
ancestor_id
est déjà défini, vous n'avez donc qu'à affecter la génération à partir de CTE.depth?
update
le tableau avec le résultat de votre CTE récursif?