La división de una trayectoria Enumeración Modelo PathString en MySQL
-
14-10-2019 - |
Pregunta
Estoy tratando de implementar un modelo de enumeración Path según libro de Joe Celko (página 38). Los atributos relevantes de mi mesa (y la mesa de soporte que solo contiene números enteros consecutivos) tener este aspecto:
Contribution
------------
ContributionID
PathString
_IntegerSeries
--------------
IntegerID
_IntegerSeries contiene números enteros de 1 a n, donde n es mayor de lo que necesitará siempre. Contribución contiene tres registros:
1 1
2 12
3 123
... y yo utilizo una versión modificada de la pregunta 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);
... para regresar con éxito un conjunto de resultados que contiene todos los superiores de ContributionID 3 en la jerarquía. Ahora, en este ejemplo, la columna de la PathString contiene valores enteros sin formato y, obviamente, nos encontramos con problemas una vez que golpeamos ContributionID 10. Así modificamos la columna de la PathString para incluir separadores:
1 1.
2 1.2.
3 1.2.3.
Ahora ... el libro no dar un ejemplo de conseguir superiores cuando los delimitadores de los usos PathString ... así que tendrán que darse cuenta de eso después. Pero nos da un ejemplo de cómo dividir un PathString (que supongo que va a ayudarme a hacer búsquedas superiores). La versión de MySQL del código de ejemplo para hacer esto es:
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 || '.');
... pero este código devuelve un conjunto de resultados vacío. Estoy haciendo algo mal, pero no estoy seguro de qué. Pensé que podría poner esto a la comunidad stackoverflow antes de molestar a Joe con un correo electrónico. Alguien tiene alguna idea?
Actualizar
consulta de Quassnoi ... modificó ligeramente un poco después de las pruebas, pero exactamente igual que su original, funcionalmente. Muy agradable. Mucho más limpio que lo que yo estaba usando. Muchas gracias.
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;
Solución
Esto se debe a ||
en MySQL
es OR
booleano, no concatenación de cadenas.
Para encontrar todos los ancestros de un Contribution
dada, utilice:
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