我在SQL中执行"树状"查询(我们称之为什么?)时遇到了一些麻烦.
看看下面的图表(表格和列名称都是丹麦语 - 抱歉):
DB图http://img197.imageshack.us/img197/8721/44060572.jpg 使用MSSQL Server 2005,目标是为每个客户(Kunde)找到最多的父组(Gruppe).
每个组可以有许多父组和许多子组.
而且,我还想知道如何显示这样的树:
Customer 1
- Parent group 1
- Child group 1
- ChildChild group n
- Child group n
- Parent group n
- ...
- ...
Customer n
- ...
另一个问题:
查询如何为所有客户获取所有组?父母和子女团体.
您可以使用CTE来动态构建"完整路径"列
--DROP TABLE Gruppe, Kunde, Gruppe_Gruppe, Kunde_Gruppe
CREATE TABLE Gruppe (
Id INT PRIMARY KEY
, Name VARCHAR(100)
)
CREATE TABLE Kunde (
Id INT PRIMARY KEY
, Name VARCHAR(100)
)
CREATE TABLE Gruppe_Gruppe (
ParentGruppeId INT
, ChildGruppeId INT
)
CREATE TABLE Kunde_Gruppe (
KundeId INT
, GruppeId INT
)
INSERT Gruppe
VALUES (1, 'Group 1'), (2, 'Group 2'), (3, 'Group 3')
, (4, 'Sub-group A'), (5, 'Sub-group B'), (6, 'Sub-group C'), (7, 'Sub-group D')
INSERT Kunde
VALUES (1, 'Kunde 1'), (2, 'Kunde 2'), (3, 'Kunde 3')
INSERT Gruppe_Gruppe
VALUES (1, 4), (1, 5), (1, 7)
, (2, 6), (2, 7)
, (6, 1)
INSERT Kunde_Gruppe
VALUES (1, 1), (1, 2)
, (2, 3), (2, 4)
;WITH CTE
AS (
SELECT CONVERT(VARCHAR(1000), REPLACE(CONVERT(CHAR(5), k.Id), ' ', 'K')) AS TheKey
, k.Name AS Name
FROM Kunde k
UNION ALL
SELECT CONVERT(VARCHAR(1000), REPLACE(CONVERT(CHAR(5), x.KundeId), ' ', 'K')
+ REPLACE(CONVERT(CHAR(5), g.Id), ' ', 'G')) AS TheKey
, g.Name
FROM Gruppe g
JOIN Kunde_Gruppe x
ON g.Id = x.GruppeId
UNION ALL
SELECT CONVERT(VARCHAR(1000), p.TheKey + REPLACE(CONVERT(CHAR(5), g.Id), ' ', 'G')) AS TheKey
, g.Name
FROM Gruppe g
JOIN Gruppe_Gruppe x
ON g.Id = x.ChildGruppeId
JOIN CTE p
ON REPLACE(CONVERT(CHAR(5), x.ParentGruppeId), ' ', 'G') = RIGHT(p.TheKey, 5)
WHERE LEN(p.TheKey) < 32 * 5
)
SELECT *
, LEN(TheKey) / 5 AS Level
FROM CTE c
ORDER BY c.TheKey
Run Code Online (Sandbox Code Playgroud)
如果您有大量的读取和罕见的修改,性能可能不是最佳的.
我无法比 Joe Celko 说得更好。问题通常是所构建的模型不适合构建层次结构,并且这些模型必须考虑层次结构的特征。是不是太深了?是不是太宽了?是不是又窄又浅?
在宽树和浅树上成功的一个关键是将层次结构中的完整路径放在一列中,就像 Celko 在第一个链接中提到的那样。