我有一个简单的自引用内存表
CREATE TABLE [Accounts]
(
Id UNIQUEIDENTIFIER NOT NULL,
[ParentAccount_Id] UNIQUEIDENTIFIER NULL,
CONSTRAINT [PK_Accounts] PRIMARY KEY NONCLUSTERED ([Id])
)
WITH
(
MEMORY_OPTIMIZED = ON,
DURABILITY = SCHEMA_AND_DATA
);
我正在努力寻找一种优雅的方法来遍历表表示的层次结构,即给定一个Account.Id,我需要获取其祖先的列表。
通常,当不使用本地编译的存储过程时,我将使用CTE或HIERARCHYID数据类型。但是,本地编译的存储过程均不支持这些方法。
所以我的问题是,我可以使用什么技术遍历与本机编译的存储过程兼容的层次结构?
样本数据和预期结果:
|Id |ParentAccounts_Id |
|---------------------------------------|--------------------------------------|
|00000000-0000-0000-0000-000000000006 |00000000-0000-0000-0000-000000000002 |
|00000000-0000-0000-0000-000000000005 |00000000-0000-0000-0000-000000000002 |
|00000000-0000-0000-0000-000000000004 |00000000-0000-0000-0000-000000000001 |
|00000000-0000-0000-0000-000000000003 |00000000-0000-0000-0000-000000000001 |
|00000000-0000-0000-0000-000000000002 |00000000-0000-0000-0000-000000000001 |
|00000000-0000-0000-0000-000000000001 |NULL |
鉴于初始ID为00000000-0000-0000-0000-000000000006我希望看到以下结果
00000000-0000-0000-0000-000000000006
00000000-0000-0000-0000-000000000002
00000000-0000-0000-0000-000000000001
答案 0 :(得分:1)
您有两个选择:
1)创建一个普通的存储过程。在内存表上运行的普通(或非本机编译的代码)称为“互操作”,并且没有真正的理由,它不会很快:
DECLARE @id UNIQUEIDENTIFIER = '00000000-0000-0000-0000-000000000006'
;WITH cte AS
(
SELECT 1 xlevel, Id, ParentAccount_Id
FROM dbo.accounts
WHERE Id = @id
UNION ALL
SELECT xlevel + 1, a.Id, a.ParentAccount_Id
FROM cte c
INNER JOIN dbo.accounts a ON c.ParentAccount_Id = a.Id
)
SELECT Id
FROM cte
或者,2)在本机编译的过程中实现循环。如果您看一下此示例I did with Fizzbuzz,它的闪电般快速-不到一秒的时间,可处理一百万次循环。
DROP PROC IF EXISTS dbo.usp_getAccounts
DROP TYPE IF EXISTS dbo.typ_accounts
GO
CREATE TYPE dbo.typ_accounts
AS TABLE
(
Id UNIQUEIDENTIFIER NOT NULL,
PRIMARY KEY NONCLUSTERED ( Id )
)
WITH ( MEMORY_OPTIMIZED = ON );
GO
DROP PROC IF EXISTS dbo.usp_getAccounts
GO
CREATE PROC dbo.usp_getAccounts
@targetAccountId UNIQUEIDENTIFIER
WITH
NATIVE_COMPILATION,
SCHEMABINDING,
EXECUTE AS OWNER
AS
BEGIN ATOMIC
WITH
(
TRANSACTION ISOLATION LEVEL = SERIALIZABLE,
LANGUAGE = N'english'
)
DECLARE @t AS dbo.typ_accounts;
WHILE ( @targetAccountId IS NOT NULL )
BEGIN
INSERT INTO @t ( Id )
SELECT @targetAccountId;
SELECT @targetAccountId = ParentAccount_Id
FROM dbo.Accounts
WHERE Id = @targetAccountId;
END
SELECT Id
FROM @t;
RETURN;
END
GO
EXEC dbo.usp_getAccounts '00000000-0000-0000-0000-000000000006'
您拥有哪种类型的卷?您使用内存表是否有特定原因?
答案 1 :(得分:0)
我想出的与本机编译的存储过程兼容的最佳方法如下:
DECLARE @targetAccountId UNIQUEIDENTIFIER = '00000000-0000-0000-0000-000000000006'
WHILE (@targetAccountId IS NOT NULL)
BEGIN
PRINT @targetAccountId
SELECT @targetAccountId = ParentAccounts_Id
FROM [im].[Accounts]
WHERE Id = @targetAccountId
END
尽管我愿意接受更好的主意,因为看到T-SQL中的循环总是让我不寒而栗!