Проверка унаследованных атрибутов в таблице SQL на основе «предков» - PullRequest
1 голос
/ 09 апреля 2010

Я использую драгоценный камень предков, чтобы помочь организовать древовидную структуру моего приложения в базе данных. Он в основном записывает информацию о предках потомков в специальный столбец, называемый «предок». Столбец предков для конкретного ребенка может выглядеть как «1/34/87», где родитель этого ребенка - 87, а затем родитель 87 - 34, а 34 - 1.

Кажется возможным, что мы могли бы выбрать строки из этой таблицы, каждая с подзапросом, который проверяет всех предков, чтобы увидеть, установлен ли определенный атрибут. Например. В моем приложении вы можете скрыть элемент и его дочерние элементы, просто установив для столбца видимости родительского элемента значение 0.

Я хочу иметь возможность найти все предметы, где ни один из их предков не спрятан. Я попытался преобразовать косые черты в запятую с помощью команды REPLACE, но для IN требовался набор целых чисел, разделенных запятыми, а не одна строка с строковыми номерами, разделенными запятыми.

Забавно, потому что я могу выполнить этот запрос в два этапа, например, получить строку, затем взять ее столбец предков, разделить идентификаторы и сделать еще один запрос, который проверяет, что идентификатор является IN, этот набор идентификаторов, и что видимость не всегда 0 и whala! Но объединить их в один запрос кажется довольно сложной задачей. Большой поиск показал несколько ответов, но ни один из них на самом деле не делает то, что я хочу.

SELECT * FROM t1 WHERE id = 99;
В столбце предков

99 указано «1/34/87»

SELECT * FROM t1 WHERE visibility = 0 AND id IN (1,34,87);

вид назад, но если это не возвращает строк, то элемент виден.

Кто-нибудь сталкивался с этим раньше и придумал решение. Я действительно не хочу идти по пути хранимых процедур. Это для приложения рельсов.

Ответы [ 2 ]

1 голос
/ 09 апреля 2010

Что вам может понадобиться, это создать функцию Split, если у вас ее еще нет ( Split a Delimited String в SQL ), а затем использовать ее как выбор IN.

Есть и другой способ, но он может ухудшить производительность на больших таблицах. Что-то вроде

SELECT  *
FROM    Table t INNER JOIN
        Table tParents      
        ON  (   t.Path LIKE CAST(tParents.ID AS VARCHAR(20)) + '/%'
                OR  t.Path LIKE +'%/' + CAST(tParents.ID AS VARCHAR(20)) + '/%'
                OR  t.Path LIKE +'%/' + CAST(tParents.ID AS VARCHAR(20)))

WHERE   t.ID = 99
AND     tParents.Visible = 0
0 голосов
/ 09 апреля 2010

Если вы настаиваете на том, чтобы уйти от хранимых / процедурных, почему бы не переключиться на вложенные множества с вашего подхода материализованных путей?

В противном случае выполните два запроса со стороны приложения (или используйте хранимую процедуру, предложенную astander).

Хорошие ссылки для иерархий в SQL здесь

EDIT: Похоже, вы храните информацию о состоянии древовидного элемента управления в базе данных.

Предполагая, что это действительно оправдано и что вам необходимо сохранить видимость в базе данных, вы можете исследовать следующие сценарии (это идеи, а не немедленные решения):

  1. открыть курсор / набор записей / любой другой подход на основе строк в вашей структуре и передать его элементу управления деревом, чтобы число обновлений и выборок из базы данных было связано с действия над деревом (отображение веток, обновление видимости, скрытие веток и т. д.). В этом случае (в зависимости от платформы) вам не нужно предварительно выбирать нужные элементы (и не выполнять оператор select каждый раз, когда пользователь закрывает или открывает ветку).

  2. обновить видимость в базе данных для всех детей. кажется, что вы обновляете видимость только на развернутом / свернутом узле (если вам нужно сохранить видимость свернутых ветвей и листьев, у вас может быть два поля; это не элегантно, но я бы тоже протестировал эту опцию)

  3. снова исследовать вложенные множества; с вложенными наборами необходимые запросы могут стать быстрее. Также становится немного легче писать SQL (здесь SQL, который возвращает узлы, у которых видны все родители, при условии, что видимость имеет tinyint (1); BIT_AND будет агрегировать AND для всех родителей в одном запросе)

    ВЫБРАТЬ узел.имя КАК имя
    ОТ узла t1 AS,
    t1 как родитель
    WHERE node.visibility = 1 AND node.lft МЕЖДУ parent.lft AND parent.rgt
    GROUP BY имя узла.
    HAVING BIT_AND (parent.visibility) = 1
    ЗАКАЗАТЬ НА node.lft

(это проверено, я взял пример с здесь и добавил видимость)

Кроме того, при тестировании и тестировании каждого решения не забудьте протестировать все операции (выбор видимых ветвей, открытие скрытых ветвей, маркировка невидимых узлов и т. Д.).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...