Fractionnement d'un chemin Enumeration Modèle PathString dans MySQL
-
14-10-2019 - |
Question
Je suis en train de mettre en œuvre un modèle de chemin Enumeration selon Joe Celko livre (page 38). Les attributs pertinents de ma table (et la table de support qui ne contient que des entiers séquentiels) ressembler à ceci:
Contribution
------------
ContributionID
PathString
_IntegerSeries
--------------
IntegerID
_IntegerSeries contient des entiers de 1 à n où n est plus grand que je ne vais jamais besoin. Contribution contient trois dossiers:
1 1
2 12
3 123
... et j'utilise une version modifiée de la requête de 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);
... pour revenir avec succès un jeu de résultats contenant tous les supérieurs de ContributionID 3 dans la hiérarchie. Maintenant, dans cet exemple, la colonne PathString détient des valeurs entières simple et évidemment nous courons en difficulté une fois que nous avons touché ContributionID 10. Nous modifions la colonne PathString pour inclure les séparateurs:
1 1.
2 1.2.
3 1.2.3.
... le livre ne donne pas un exemple d'obtenir des supérieurs lorsque les PathString ... donc délimiteurs utilisations que je vais devoir comprendre cela plus tard. Mais il ne donne un exemple sur la façon de diviser un PathString (que je devine va me aider faire des recherches supérieures). La version MySQL du code exemple pour ce faire est:
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 || '.');
... mais ce code renvoie un jeu de résultats vide. Je fais quelque chose de mal, mais je ne sais pas quoi. Je mettrais Figured ceci à la communauté stackoverflow avant Joe prendre la peine avec un e-mail. Quelqu'un at-il des pensées?
UPDATE
La requête de Quassnoi ... légèrement modifié un peu après le test, mais exactement le même que son origine fonctionnelle. Très agréable. Beaucoup plus propre que ce que j'utilisais. Un grand merci.
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;
La solution
En effet, dans ||
MySQL
est OR
booléen, pas concaténation de chaînes.
Pour tous les ancêtres d'un Contribution
donné, utilisez:
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