我有一个大约有220万行的表,如果行有一行,我希望每行最顶层的父(root)。下面你可以看到我的查询只有一行。
此语句大约需要45秒,这需要一些时间来运行此查询。并非所有人都拥有父密钥,因此大约有100万人没有父母。这可能是值得思考的问题。但希望你们中的一些人能够更好地解决这个问题,我希望你能分享它。
WITH allRows
AS (SELECT Organisasjonsnummer AS ID,
Navn,
Organisasjonsnummer [RootId],
Navn [RootName]
FROM Virksomhetstjeneste.Virksomhet
WHERE Hovedenhet_id IS NULL
UNION ALL
SELECT a1.Organisasjonsnummer AS ID,
a1.Navn,
a2.[RootId],
a2.[RootName]
FROM Virksomhetstjeneste.Virksomhet a1
JOIN allRows a2
ON a2.ID = a1.Hovedenhet_id)
SELECT *
FROM allRows
Where ID = 980659763
结果
ID Navn RootId RootName
980659763 NILLE AS AVD ALTA 953581477 NILLE AS
答案 0 :(得分:1)
我多次成为hierarchyid
的粉丝。以下是我如何根据您的情况来做这件事。
首先要做的事情:请原谅我没有使用你的表名和列名;我不会说挪威语,在英语之间来回走动,这对我来说很容易出错。所以这就是设置:
USE [tempdb];
IF OBJECT_ID('dbo.myTable') IS NOT NULL
DROP TABLE [dbo].[myTable];
CREATE TABLE [dbo].[myTable]
(
[ID] INT NOT NULL ,
CONSTRAINT [PK_myTable] PRIMARY KEY ( [ID] ) ,
[ParentID] INT NULL ,
[Name] VARCHAR(50) NOT NULL ,
[Path] HIERARCHYID NULL,
[Root] AS [Path].GetAncestor([Path].GetLevel() - 1) PERSISTED
);
INSERT INTO [dbo].[myTable]
( [ID], [ParentID], [Name] )
VALUES ( 1, NULL, '1' ),
( 2, 1, '2' ),
( 3, 1, '3' ),
( 4, 2, '4' );
WITH [allRows]
AS (
SELECT [ID] ,
[ParentID] ,
CAST(CONCAT('/', [ID], '/') AS VARCHAR(MAX)) AS [Path]
FROM [dbo].[myTable]
WHERE [ParentID] IS NULL
UNION ALL
SELECT [child].[ID] ,
[child].[ParentID] ,
CAST(CONCAT([parent].[Path], [child].[ID], '/') AS VARCHAR(MAX)) AS [Path]
FROM [dbo].[myTable] AS [child]
JOIN [allRows] AS [parent]
ON [parent].[ID] = [child].[ParentID]
)
UPDATE [m]
SET [m].[Path] = [a].[Path]
FROM [dbo].[myTable] AS [m]
JOIN [allRows] AS [a]
ON [a].[ID] = [m].[ID];
这只是走私父/子层次结构的标准递归CTE。这里的诀窍是,我正在计算一些我可以用作hierarchyid
的东西。遍历层次结构后,我使用计算的层次结构更新基表。
由于您提到您的表格很大,您可能希望批量处理这些更新。我将此作为练习留给读者。另请注意,这是一次性操作(尽管您必须使[Path]
列保持最新的插入/更新/删除;我还将此作为练习留给读者。)
现在您已经将行级存储在行中,您可以做魔术:
SELECT [child].[ID] ,
[child].[Name] ,
[root].[ID] ,
[root].[Name]
FROM [dbo].[myTable] AS [child]
JOIN [dbo].[myTable] AS [root]
ON [root].[Path] = [child].[Root]
WHERE child.[ID] = 4;
这就是说我现在可以通过加入获得给定ID的顶级祖先。将根作为持久计算列是a)花哨和b)不必要的;它只是使最后一个选择更清洁。
如果您不想这样做,可以完全删除[Root]
列,然后将联接谓词变为[root].[Path] = [child].[Path].GetAncestor([Path].GetLevel() - 1)
。
最后,请记住hierarchyid
数据类型本机可索引。因此,您可以对[Path]
,[Root]
或两者进行索引,这样可能会提高性能。