Разделение пути Модель перечисления PathString в MySQL - PullRequest
2 голосов
/ 31 декабря 2010

Я пытаюсь реализовать модель перечисления путей в соответствии с книгой Джо Селко (стр. 38).Соответствующие атрибуты моей таблицы (и вспомогательной таблицы, которая содержит только последовательные целые числа) выглядят так:

Contribution
------------
ContributionID
PathString

_IntegerSeries
--------------
IntegerID

_IntegerSeries содержит целые числа от 1 до n, где n больше, чем мне когда-либо понадобится.Вклад содержит три записи:

1  1
2  12
3  123

... и я использую модифицированную версию запроса Джо:

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);

..., чтобы успешно вернуть набор результатов, содержащий все ContributionID 3начальство в иерархии.Теперь, в этом примере, столбец PathString содержит простые целочисленные значения, и, очевидно, у нас возникнут проблемы, когда мы нажмем ContributionID 10. Поэтому мы изменяем столбец PathString, чтобы включить разделители:

1   1.
2   1.2.
3   1.2.3.

Сейчас ...не дает пример получения начальных классов, когда PathString использует разделители ... поэтому я должен выяснить это позже.Но он дает пример того, как разделить PathString (что, я думаю, поможет мне выполнить превосходный поиск).Версия примера кода MySQL для этого:

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 || '.');

... но этот код возвращает пустой набор результатов.Я делаю что-то не так, но я не уверен, что.Я подумал, что я расскажу об этом сообществу stackoverflow, прежде чем беспокоить Джо электронной почтой.У кого-нибудь есть мысли?


ОБНОВЛЕНИЕ


Запрос Quassnoi ... немного изменен после тестирования, но точно так же, как его оригинал функционально.Очень хорошо.Гораздо чище, чем я использовал.Большое спасибо.

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;

1 Ответ

2 голосов
/ 31 декабря 2010

Это потому, что || в MySQL является логическим OR, а не конкатенацией строк.

Чтобы найти всех предков данного Contribution, используйте:

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
...