El gráfico se utilizó para implementar la subordinación entre empleados, en lugar del método antepasado-hijo utilizado anteriormente en la tabla de departamentos.
La experiencia resultó ser exitosa, tal vez sea útil para alguien y ayude a ahorrar tiempo. En un momento, estaba buscando una implementación en pqSQL, pero aparentemente tenía mal aspecto. Tuve que implementarlo yo mismo. Lo que, en general, es incluso lo mejor, la tarea es interesante, siempre es bueno hacer algo con tus propias manos, para que no se pierda el tiempo.
Los datos de entrada
En general, existe una tabla estándar "posición de empleado" con la identificación de la clave principal . Los puestos tienen una jerarquía de subordinación "jefe-empleado". La idea es que los enlaces entre publicaciones se almacenen en un gráfico de entidad separado .
Para encontrar una ruta en el gráfico, se utilizó el algoritmo de Dijkstra, se puede encontrar una descripción general, por ejemplo, aquí
Salida
- Lista de empleados subordinados para esto
- Lista de jefes de este empleado
- ¿Es el empleado un subordinado para esto?
- Lista de empleados subordinados para este (ruta de jefe a empleado)
Implementación usando PL / pgSQL
Guardar un gráfico como tabla de aristas
Los vértices son los valores de identificación de la tabla de destino.
CREATE TABLE graph
(
vertex integer NOT NULL , --id
edge integer NOT NULL , --id
vertex_order integer NOT NULL -- ( 0 , 1 )
);
Para generar la identificación del borde, use la secuencia
CREATE SEQUENCE enge_seq OWNED BY graph.edge;
Llenar la mesa del borde
Se utilizan dos operaciones INSERT para insertar una nueva arista (vértices id0, id1 )
-- id
new_id = nextval('enge_seq');
--
INSERT INTO graph (vertex , edge , vertex_order ) VALUES ( id0 , new_id , 0 );
--
INSERT INTO graph (vertex , edge , vertex_order ) VALUES ( id1 , new_id , 1 );
Recuperar una lista de empleados subordinados para un current_id determinado
SELECT
id
FROM
graph
WHERE
vertex_order = 1 AND
edge IN (SELECT edge FROM graph WHERE vertex = current_id AND vertex_order = 0 );
Obtener la lista de jefes para un current_id determinado
SELECT
id
FROM
graph
WHERE
vertex_order = 0 AND
edge IN (SELECT edge FROM graph WHERE vertex = current_id AND vertex_order = 1 );
Generación de una matriz de disponibilidad (algoritmo de Dijkstra) a partir de un vértice dado start_id
Creando una tabla temporal tmp_matrix
CREATE TEMPORARY TABLE tmp_matrix
AS
(
SELECT
DISTINCT vertex ,
FALSE AS label ,
999999 AS distance ,
FALSE AS is_finish
FROM
graph
);
Población inicial de la tabla tmp_matrix
UPDATE tmp_matrix
SET label = TRUE , distance = 0
WHERE vertex = current_id ;
current_id = start_id ;
SELECT
distance
INTO
current_distance
FROM
tmp_matrix
WHERE
vertex = current_id;
SELECT
EXISTS (SELECT 1 FROM tmp_matrix WHERE label = FALSE )
INTO
not_visit;
Cumplimentación de la matriz de disponibilidad
WHILE not_visit
LOOP
FOR v_rec IN
SELECT
*
FROM
tmp_matrix
WHERE
NOT label AND
--
vertex IN ( SELECT
id
FROM
graph
WHERE
vertex_order = 1 AND
edge IN (SELECT
edge
FROM
graph
WHERE
vertex = current_id AND vertex_order = 0 ))
LOOP
--
IF v_rec.distance > (current_distance +1)
THEN
UPDATE tmp_matrix SET distance = (current_distance +1) WHERE vertex = v_rec.vertex;
END IF ;
--
IF SELECT
NOT EXISTS
(
SELECT 1 FROM graph WHERE vertex = v_rec.vertex AND vertex_order = 0
)
THEN
UPDATE tmp_matrix SET label = TRUE , is_finish = TRUE WHERE vertex = v_rec.vertex;
END IF ;
END LOOP;
UPDATE tmp_matrix SET label = TRUE WHERE vertex = current_id ;
--
SELECT
vertex
INTO
current_id
FROM
tmp_matrix
WHERE
NOT label AND
distance < 999999 ;
SELECT
distance
INTO
current_distance
FROM
tmp_matrix
WHERE
vertex = current_id ;
SELECT
EXISTS (SELECT 1 FROM tmp_matrix WHERE label = FALSE )
INTO
not_visit ;
IF current_id IS NULL
THEN
not_visit = FALSE ;
END IF;
END LOOP;
Devuelve la matriz de disponibilidad resultante
SELECT
vertex ,
label ,
distance ,
is_finish
FROM
tmp_matrix
WHERE
distance != 999999 ;
Si el empleado con check_id es un subordinado para el start_id dado
Obtenga la matriz de disponibilidad para start_id (ver arriba).
IF EXISTS
( SELECT distance FROM tmp_matrix WHERE vertex = check_id )
THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
Lista de empleados subordinados para este (ruta desde boss start_id hasta employee finish_id)
Obtenga la matriz de disponibilidad para start_id (ver arriba).
Complete la tabla de ruta entre las tablas start_id y finish_id
current_id = finish_id ;
result[1] = finish_id ;
WHILE current_id != start_id
LOOP
SELECT
par.id
FROM
( SELECT
id
FROM
graph
WHERE
vertex_order = 0 AND
edge IN (SELECT
edge
FROM
graph
WHERE
vertex = current_id AND vertex_order = 1 )) par
JOIN tmp_matrix m ON ( par.id = m.vertex )
INTO
parent_id
LIMIT 1 ;
SELECT
array_append( result , parent_id )
INTO
result ;
--
current_id = parent_id ;
END LOOP;
Como resultado , la ruta en la matriz de resultados se formará como un conjunto de id en orden inverso. Para facilitar la visualización, la matriz se puede invertir de cualquier forma.