2015-05-04 2 views
3

У меня есть иерархия определения/поле отношений, которая распространилась по 3 таблицы:MSSQL рекурсивно выбрать все строки, связанные

CREATE TABLE ProductDefinition 
(
    ProductDefinitionId int, 
    Name nvarchar(10), 
) 

CREATE TABLE ProductDefinitionRelation 
(
    ProductDefinitionId int, 
    ParentProductDefinitionId int 
) 

CREATE TABLE ProductDefinitionField 
(
    ProductDefinitionFieldId int, 
    ProductDefinitionId int, 
    Name nvarchar(10) 
) 

Идея заключается в том, что это позволяет редактору CMS поделиться общими свойствами по объектов, сохраняя время администрирования администратора.

Структура от третьего лица, поэтому ее нельзя изменить, но теперь мне нужно выбрать все родительские свойства (n deep), поэтому, если у вас есть иерархия Grand Parent> Parent> Child, у ребенка будут все свойства, определенные на Великий Родитель/Родитель.

У меня довольно близко, но проблема возникает, когда у ребенка нет никаких свойств, он отфильтровывается INNER JOIN в CTE.

Кто-нибудь знает, как я могу избежать этого Child2 в этом примере, все равно нужно иметь все опоры Великого Родительского/Родительского?

я установки скрипку здесь: http://www.sqlfiddle.com/#!6/08dc3/4, но мой код ниже:

INSERT INTO ProductDefinition 
    VALUES (1,'G. Parent'),(2,'Parent'),(3,'Child1'),(4,'Child2'),(5,'Child3'); 

INSERT INTO ProductDefinitionField 
VALUES 
    (1,1,'G. Field'), 
    (2,2,'P. Field'), 
    (3,3,'C. Field'), 
    (4,5,'C. Field'); 

INSERT INTO ProductDefinitionRelation 
VALUES (2,1),(3,2),(4,2),(5,2); 

WITH Fields 
AS 
    (
     SELECT 
      pd.ProductDefinitionId 
      , pd.Name AS [ProductDefinitionName] 
      , pdf.ProductDefinitionFieldId 
      , pdf.Name AS [ProductDefinitionFieldName] 
     FROM 
      ProductDefinition pd 
       LEFT JOIN ProductDefinitionRelation pdr ON pd.ProductDefinitionId = pdr.ProductDefinitionId 
       LEFT JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId 
     WHERE 
      pdr.ProductDefinitionId IS NULL 

    UNION ALL 

     SELECT 
      pd.ProductDefinitionId 
      , pd.Name AS [ProductDefinitionName] 
      , pdf.ProductDefinitionFieldId 
      , pdf.Name AS [ProductDefinitionFieldName] 
     FROM 
      Fields f 
       JOIN ProductDefinitionRelation pdr ON f.ProductDefinitionId = pdr.ParentProductDefinitionId 
       JOIN ProductDefinition pd ON pdr.ProductDefinitionId = pd.ProductDefinitionId 
       JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId 

    UNION ALL 

     SELECT 
      pd.ProductDefinitionId 
      , pd.Name AS [ProductDefinitionName] 
      , f.ProductDefinitionFieldId 
      , f.ProductDefinitionFieldName AS [ProductDefinitionFieldName] 
     FROM 
      Fields f 
       JOIN ProductDefinitionRelation pdr ON f.ProductDefinitionId = pdr.ParentProductDefinitionId 
       JOIN ProductDefinition pd ON pdr.ProductDefinitionId = pd.ProductDefinitionId 
       JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId 
) 
SELECT DISTINCT 
    * 
FROM 
    Fields 
ORDER BY 
    ProductDefinitionName 

ответ

0
WITH FIELDS AS 
    (
     SELECT 
      pd.ProductDefinitionId 
      , pd.ProductDefinitionId [ChildDefinitionID] 
      , pd.Name AS [ProductDefinitionName] 
      , pdf.ProductDefinitionFieldId 
      , pdf.Name AS [ProductDefinitionFieldName] 
     FROM 
      ProductDefinition pd 
      LEFT JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId 

    UNION ALL 

     SELECT 
      f.ProductDefinitionId 
      , pd.ProductDefinitionId [ChildDefinitionID] 
      , f.ProductDefinitionName AS [ProductDefinitionName] 
      , pdf.ProductDefinitionFieldId 
      , pdf.Name AS [ProductDefinitionFieldName] 
     FROM 
      Fields f 
       JOIN ProductDefinitionRelation pdr ON f.ChildDefinitionID = pdr.ProductDefinitionId 
       JOIN ProductDefinition pd ON pdr.ParentProductDefinitionId = pd.ProductDefinitionId        
       JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId  
) 
SELECT DISTINCT 
    * 
FROM 
    Fields 
ORDER BY 
    ProductDefinitionName 

http://www.sqlfiddle.com/#!6/89721b/11

Идея:
Используйте два поля для отслеживания рекурсии:

  • ProductDefinitionId содержит идентификаторы полей, которые, наконец, принадлежат
  • ChildDefinitionID содержит идентификатор дочернего элемента, отношение родителя проверяется во время рекурсии; первоначально это идентификатор childs
+0

Я пробовал, что проблема заключается в том, что вы потеряете все свойства дедушки/родителя для Ребенка. У меня есть чувство, что решение идет по этим линиям, хотя я продолжу играть. – Tim

+0

Что вы подразумеваете под «потерять все свойства бабушки и дедушки»? Если вы выполняете запрос в скрипте, все свойства родительского/грандиозного родителя есть. – flo

+0

Если вы сравните его с моим оригиналом, вы получите: Child1 - C. Field, P. Field и G. Field Только что возвращает Child1 - C. Поле – Tim

Смежные вопросы