Как я могу получить иерархические значения из запроса ниже?

8

У меня есть таблица с именем Categoryстолбца CategoryID. В той же таблице есть столбец ссылок fParentCategoryID.

Мне нужно, чтобы все идентификаторы категорий и идентификаторы их подкатегорий были разделены запятой. Например: если ID родительской категории 10 равен 1, а ID родительской категории 20 равен 10, то когда я печатаю ID 20 категории, мне нужно вывести как 1, так и 10 в качестве его родителей в значениях, разделенных запятыми.

Я попытался запрос ниже, но я получаю NULLдля ParChildстолбца. Пожалуйста помоги.

;WITH
  cteReports 
  AS
(
SELECT c.CategoryID,
       c.fParentCategoryID,
       [level] = 1,
       ParChild=cast(CAST(c.fParentCategoryID AS VARCHAR(200)) + ',' + CAST(c.CategoryID AS VARCHAR(200)) AS VARCHAR(MAX))
FROM   retail.Category c
WHERE c.fParentCategoryID is NULL
UNION ALL
SELECT c.CategoryID,
       c.fParentCategoryID,
       [level] + 1,
       ParChild = ParChild + ',' + CAST(c.CategoryID AS VARCHAR(200))
FROM   retail.Category c
        JOIN cteReports r
            ON  c.fParentCategoryID = r.CategoryID

)

SELECT *
FROM   cteReports cr 

используйте этот скрипт для создания и заполнения таблицы. (примечание: для тела вопроса существует ограничение в 30 КБ. Поэтому мне пришлось использовать pastebin, чтобы скопировать код и сослаться на него)

mayooran
источник

Ответы:

3

Я смог скопировать ваши результаты с данными вашего примера.

Ваша проблема заключается в том, что в «базовом» случае рекурсивного CTE (первого оператора select) вы получаете записи, в которых fParentCategoryID имеет значение null, и приводите fParentCategoryID к символьному столбцу, готовому добавить «детей». Однако на этом этапе 'string' все еще является значением NULL (попробуйте его с помощью SELECT CAST (NULL AS VARCHAR (200)) или чего-то подобного).

Затем второй оператор выбора пытается добавить другие строковые значения к NULL, но по умолчанию опция базы данных «concat null приводит к нулю» говорит, что если вы попытаетесь объединить что-либо с NULL-значением, вы все равно просто получите NULL - вместо того, чтобы рассматривать его как пустая строка.

Вы можете установить для этого запроса значение CONCAT_NULL_YIELDS_NULL OFF, хотя это устарело и в конечном итоге будет удалено в будущей версии SQL Server (так что вам, вероятно, не следует добавлять его в производственный код!)

Лучше всего в первом операторе select вместо приведения fParentCategoryID к строке просто приведите CategoryID - мы уже знаем, что родительский объект должен быть пустым, поскольку они являются NULL.

SELECT c.CategoryID,
   c.fParentCategoryID,
   [level] = 1,
   ParChild=cast(CAST(c.CategoryID AS VARCHAR(200)) AS VARCHAR(MAX))
FROM   retail.Category c
WHERE c.fParentCategoryID is NULL

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

Вероятно, требуется некоторая очистка значения ParChild, которое он выдает, когда вы получаете значения типа ", 461 464", так что вы можете удалить начальную запятую.

seventyeightist
источник