尝试这样的事情:
DECLARE @Source TABLE (
Name VARCHAR(10) PRIMARY KEY,
XmlCol XML NOT NULL
)
DECLARE @Root VARCHAR(10)='A'
INSERT INTO @Source VALUES
('A',CONVERT(XML,'<E><B Id="b1" Type="0" /><B Id="D" Type="1" /><B Id="b2" Type="0" /></E>')),
('D',N'<E><B Id="b3" Type="0" /><B Id="G" Type="1" /></E>'),
('F',N'<E><B Id="b4" Type="0" /></E>'),
('G',N'<E><B Id="b5" Type="0" /></E>')
DECLARE @Temp1 TABLE (
ID INT IDENTITY PRIMARY KEY,
Name VARCHAR(10) NOT NULL,
Type INT NOT NULL,
Value VARCHAR(10) NOT NULL
)
INSERT INTO @Temp1
SELECT Name, xTree.b.value('@Type', 'int') AS Type, xTree.b.value('@Id', 'varchar(10)') AS Value
FROM @Source
CROSS APPLY [XmlCol].nodes('/E/B') AS xTree(b)
DECLARE @Temp2 TABLE (
ID INT PRIMARY KEY,
Name VARCHAR(10) NOT NULL,
Type INT NOT NULL,
Value VARCHAR(10) NOT NULL,
Position INT NOT NULL
)
INSERT INTO @Temp2
SELECT *, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY ID) AS Position
FROM @Temp1
DECLARE @Temp3 TABLE (
Name VARCHAR(10) NOT NULL,
Type INT NOT NULL,
Value VARCHAR(10) NOT NULL,
Position FLOAT NOT NULL,
Level INT NOT NULL,
PRIMARY KEY (Name, Position)
)
;WITH CTE AS (
SELECT Name, Type, Value, CONVERT(FLOAT,Position) AS Position, 0 AS Level
FROM @Temp2 WHERE Type=0
UNION ALL
SELECT t1.Name, t2.Type, t2.Value,
t1.Position+t2.Position*POWER(CONVERT(FLOAT,0.1),1+t2.Level),
t2.Level+1 AS Level
FROM @Temp2 t1
INNER JOIN CTE t2 ON t2.Name=t1.Value
WHERE t1.Type=1
)
INSERT INTO @Temp3
SELECT * FROM CTE
SELECT Value
FROM (
SELECT Value, 0 AS Extra, Position
FROM @Temp3 WHERE Name=@Root
UNION ALL
SELECT Value, 1 AS Extra, Position
FROM @Temp3 WHERE Value NOT IN (
SELECT Value
FROM @Temp3 WHERE Name=@Root
)
) u
ORDER BY Extra, Position
几点观察:
在 XML 中,应始终引用属性的值
不是很清楚你想要给定根的树之外的值的顺序(在这个例子中,只有 b4 不是从 A 开始的树的一部分;如果有多个这样的值,在多个其他树中,目前尚不清楚哪个是所需的顺序)
使用更复杂的 CTE 可以避免使用表变量,但我认为它们有助于提高性能
我假设每个级别最多有 10 个子节点;如果子节点比较多,可以把0.1改成0.01,比如