【问题标题】:tree structure in different tables不同表中的树结构
【发布时间】:2015-10-24 20:32:27
【问题描述】:

我有四张桌子,

  • Level1 (id, name, idFather, LevelFather)
  • Level2 (id, name, idFather, LevelFather)
  • Level3 (id, name, idFather, LevelFather)
  • Level4 (id, name, idFather, LevelFather)

这个逻辑允许构建一棵树,其中叶子是Level4中的项目,他的父亲可以取1、2或3层。同理,Level3中的项目,可以有一个父亲在2 o 1.

对于给定的 id 和 level,是否有任何查询可以获取下面的树,直到给定的 level?

例如,我们是否有下一个数据:

Level1 - 001, GroupEnterprise1, 001, 1

Level2 - 001-1, Enterprise1, 001, 1

Level2 - 001-2, Enterprise2,001, 1

Level3 - 002-1、Enterprise3、001-1、2

Level4 - 003-1,办公室 1,001-1,3

Level4 - 003-2,办公室 2,001-2,3

Level4 - 003-3, Office 3, 001-2,3

Level4 - 003-4,办公室 4,001-1,3

我可以查询所有办公室(第 4 级的项目),即 GroupEnterprise1 集团的女儿、孙女和曾孙女,或者 Enterprise3 的女儿办公室,或者 GroupEnterprise1 的女儿企业。

在我希望构建树之前,查询的参数是 Id、Level 和 Level。

【问题讨论】:

  • 你应该提供一些样本数据和想要的结果

标签: sql sql-server tsql


【解决方案1】:

我不确定我是否完全理解你想要做什么。如果您需要一个层次结构,您应该使用一个名为“Levels”的表,并将您的所有级别信息都放在该表中。你不需要4张桌子。您可以执行自加入以轻松返回父信息。

问题在于,为了在链条中移动,您可能必须使用某种循环。这通常在 SQL 语句中避免,因为查询优化器必须为循环的每次迭代生成一个执行计划(这是低效的)。可以只使用 SQL,但我建议提取包含所有信息的表,并使用不适合基于集合的操作的非 SQL 编程语言对其进行解析。

下面是一些示例代码,它使用一个表来处理所有 4 个级别。在表中构建树后,您只需要通过 FOR 循环来显示您想要的方式。

--Creates Temp table (This table will expire upon connection close)
CREATE TABLE [#Levels] ([id] INT, [name] NVARCHAR(256), [level] INT, [idFather] INT);

--Populate Temp table with some sample data
INSERT INTO #Levels VALUES (1,'AbsoluteParent',1,null)
INSERT INTO #Levels VALUES (2,'ChildItem1',2,1)
INSERT INTO #Levels VALUES (3,'ChildItem2',2,1)
INSERT INTO #Levels VALUES (4,'GrandChild',3,2)

--Display populated table
SELECT * FROM [#Levels]

--Create 2 instances of our Temp table and join (id > idFather) so that we can return information about the parent table.  
SELECT [T1].[name] AS 'Name'
    , [T2].[name] AS 'Parent Name'
FROM [#Levels] AS T1
    LEFT JOIN [#Levels] T2 ON [T1].[idFather] = [T2].[id]

--We can even link another instance of our Temp table and give information about grandparents! 
SELECT [T1].[name] AS 'Name'
    , [T2].[name] AS 'Parent Name'
    , [T3].[name] AS 'Grand Parent Name' 
FROM [#Levels] AS T1
    LEFT JOIN [#Levels] T2 ON [T1].[idFather] = [T2].[id]
    LEFT JOIN [#Levels] T3 ON [T2].[idFather] = [T3].[id]

也许您正在寻找的是一个递归公用表表达式,它将输出反馈给函数以递归地显示所有子项。这是一个微软的例子:https://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

我稍微简化了微软的例子:

 -- Create a temp Employee table.
CREATE TABLE #MyEmployees
(
    EmployeeID smallint NOT NULL,
    FirstName nvarchar(30)  NOT NULL,
    LastName  nvarchar(40) NOT NULL,
    Title nvarchar(50) NOT NULL,
    ManagerID int NULL, 
);
-- Populate the table with values.
INSERT INTO #MyEmployees VALUES 
 (1, N'Ken', N'Sánchez', N'Chief Executive Officer',NULL)
,(273, N'Brian', N'Welcker', N'Vice President of Sales',1)
,(274, N'Stephen', N'Jiang', N'North American Sales Manager',273)
,(275, N'Michael', N'Blythe', N'Sales Representative',274)
,(276, N'Linda', N'Mitchell', N'Sales Representative',274)
,(285, N'Syed', N'Abbas', N'Pacific Sales Manager',273)
,(286, N'Lynn', N'Tsoflias', N'Sales Representative',285)
,(16,  N'David',N'Bradley', N'Marketing Manager',273)
,(23,  N'Mary', N'Gibson', N'Marketing Specialist',16);


WITH DirectReports (ManagerID, EmployeeID, Title, Level)
AS
(
    SELECT e.ManagerID, e.EmployeeID, e.Title, 0 AS Level
    FROM #MyEmployees AS e
    WHERE e.ManagerID is null

    UNION ALL

    SELECT e.ManagerID, e.EmployeeID, e.Title, d.Level + 1
    FROM #MyEmployees AS e
    INNER JOIN DirectReports AS d
    ON e.ManagerID = d.EmployeeID
)
SELECT ManagerID, EmployeeID, Title, Level
FROM DirectReports

【讨论】:

  • 表已经创建。但是,像这样的东西可以与为级别构建表的中间查询一起使用。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多