CREATE DEFINER = 'root'@'localhost'
PROCEDURE test.GetHierarchyUsers(IN StartKey INT)
BEGIN
-- prepare a hierarchy level variable
SET @hierlevel := 00000;
-- prepare a variable for total rows so we know when no more rows found
SET @lastRowCount := 0;
-- pre-drop temp table
DROP TABLE IF EXISTS MyHierarchy;
-- now, create it as the first level you want...
-- ie: a specific top level of all "no parent" entries
-- or parameterize the function and ask for a specific "ID".
-- add extra column as flag for next set of ID's to load into this.
CREATE TABLE MyHierarchy AS
SELECT U.ID
, U.Parent
, U.`name`
, 00 AS IDHierLevel
, 00 AS AlreadyProcessed
FROM
Users U
WHERE
U.ID = StartKey;
-- how many rows are we starting with at this tier level
-- START the cycle, only IF we found rows...
SET @lastRowCount := FOUND_ROWS();
-- we need to have a "key" for updates to be applied against,
-- otherwise our UPDATE statement will nag about an unsafe update command
CREATE INDEX MyHier_Idx1 ON MyHierarchy (IDHierLevel);
-- NOW, keep cycling through until we get no more records
WHILE @lastRowCount > 0
DO
UPDATE MyHierarchy
SET
AlreadyProcessed = 1
WHERE
IDHierLevel = @hierLevel;
-- NOW, load in all entries found from full-set NOT already processed
INSERT INTO MyHierarchy
SELECT DISTINCT U.ID
, U.Parent
, U.`name`
, @hierLevel + 1 AS IDHierLevel
, 0 AS AlreadyProcessed
FROM
MyHierarchy mh
JOIN Users U
ON mh.Parent = U.ID
WHERE
mh.IDHierLevel = @hierLevel;
-- preserve latest count of records accounted for from above query
-- now, how many acrual rows DID we insert from the select query
SET @lastRowCount := ROW_COUNT();
-- only mark the LOWER level we just joined against as processed,
-- and NOT the new records we just inserted
UPDATE MyHierarchy
SET
AlreadyProcessed = 1
WHERE
IDHierLevel = @hierLevel;
-- now, update the hierarchy level
SET @hierLevel := @hierLevel + 1;
END WHILE;
-- return the final set now
SELECT *
FROM
MyHierarchy;
-- and we can clean-up after the query of data has been selected/returned.
-- drop table if exists MyHierarchy;
END
Potrebbe sembrare ingombrante, ma di utilizzare questo, do
call GetHierarchyUsers(5);
(o qualsiasi altra cosa ID chiave che si desidera trovare l'albero gerarchico per).
La premessa è iniziare con la CHIAVE con cui si sta lavorando. Quindi, usalo come base per unirti alla tabella degli utenti, ma in base all'ID del genitore della prima voce. Una volta trovato, aggiorna la tabella temporale per non tentare di unirsi a quella chiave di nuovo nel ciclo successivo. Quindi continua fino a quando non è possibile trovare più chiavi ID "parent".
Ciò restituirà l'intera gerarchia di record al padre, indipendentemente dalla profondità del nesting. Tuttavia, se vuoi solo il genitore FINALE, puoi usare la variabile @hierlevel per restituire solo l'ultima nel file aggiunto, o ORDER BY e LIMIT 1
Bill Karwin è corretto. MySQL non ha alcuna funzione per le query ricorsive proprio come 'SQL Server' in quanto ha' CTE'. ma il comportamento della ricorsione può ancora essere simulato. ': D' –
Non penso che si possa fare la ricorsione in MySQL con una singola query, ma ho fatto una gerarchia genitoriale simile interrogando tramite stored procedure che continuano a cercare il livello genitore finché non sono state trovate più voci genitoriali ... ma fatte tramite una tabella temporanea che viene cancellata al termine ... funzionerebbe per te? – DRapp
@DRapp: Probabilmente sarebbe accettabile. Sarebbe divertente imparare in entrambi i modi –