Dividere un percorso Enumeration Modello PathString in MySQL
-
14-10-2019 - |
Domanda
Sto cercando di implementare un modello di enumerazione percorso secondo di Joe Celko libro (pagina 38). Gli attributi rilevanti della mia tavola (e la tabella di supporto che contiene solo numeri interi sequenziali) simile a questa:
Contribution
------------
ContributionID
PathString
_IntegerSeries
--------------
IntegerID
_IntegerSeries contiene numeri interi da 1 a n, dove n è più grande di quanto avrete bisogno. Contributo contiene tre record:
1 1
2 12
3 123
... e io uso una versione modificata di interrogazione di Joe:
SELECT SUBSTRING( c1.PathString
FROM (s1.IntegerID * CHAR_LENGTH(c1.ContributionID))
FOR CHAR_LENGTH(c1.ContributionID)) AS ContID
FROM
Contribution c1, _IntegerSeries s1
WHERE
c1.ContributionID = 3
AND s1.IntegerID <= CHAR_LENGTH(c1.PathString)/CHAR_LENGTH(c1.ContributionID);
... per tornare con successo un set di risultati contenente tutti i superiori di ContributionID 3 nella gerarchia. Ora, in questo esempio, la colonna PathString detiene valori pianura interi e, ovviamente, ci imbattiamo in problemi una volta che ci ha colpito ContributionID 10. Quindi modifichiamo la colonna PathString per includere i separatori:
1 1.
2 1.2.
3 1.2.3.
Ora ... il libro non dare un esempio di ottenere superiori quando gli usi PathString delimitatori ... quindi dovrò figura che più tardi fuori. Ma lo fa dare un esempio di come dividere un PathString (che sto cercando di indovinare che sta per aiutarmi a fare le ricerche superiori). La versione di MySQL del codice di esempio per fare questo è:
SELECT SUBSTRING( '.' || c1.PathString || '.'
FROM s1.IntegerID + 1
FOR LOCATE('.', '.' || c1.PathString || '.', s1.IntegerID + 1) - s1.IntegerID - 1) AS Node
FROM _IntegerSeries s1, Contribution c1
WHERE
SUBSTRING('.' || c1.PathString || '.' FROM s1.IntegerID FOR 1) = '.'
AND IntegerID < CHAR_LENGTH('.' || c1.PathString || '.');
... ma questo codice restituisce un set di risultati vuoto. Sto facendo qualcosa di sbagliato, ma io non sono sicuro di cosa. Ho pensato di mettere questo alla comunità StackOverflow prima di preoccuparsi di Joe con una e-mail. Qualcuno ha qualche idea?
UPDATE
interrogazione di Quassnoi ... leggermente modificata un po 'dopo il test, ma esattamente lo stesso come il suo originale punto di vista funzionale. Molto bella. Molto più pulito di quello che stavo usando. Un grande grazie.
SET @contributionID = 3;
SELECT ca.*
FROM
Contribution c INNER JOIN _IntegerSeries s
ON s.IntegerID < @contributionID AND SUBSTRING_INDEX(c.PathString, '.', s.IntegerID) <> SUBSTRING_INDEX(c.PathString, '.', s.IntegerID + 1)
INNER JOIN Contribution ca
ON ca.PathString = CONCAT(SUBSTRING_INDEX(c.PathString, '.', s.IntegerID), '.')
WHERE c.ContributionID = @contributionID;
Soluzione
This is because ||
in MySQL
is boolean OR
, not string concatenation.
To find all ancestors of a given Contribution
, use:
SELECT ca.*
FROM Contribution с
JOIN IntegerSeries s
ON IntegerID < CHAR_LENGTH(c.path)
AND SUBSTRING_INDEX(c.path, '.', IntegerID) <> SUBSTRING_INDEX(c.path, '.', IntegerID + 1)
JOIN Contribution ca
ON ca.path = CONCAT(SUBSTRING_INDEX(c.path, '.', IntegerID), '.')
WHERE c.ContributionID = 3