从头开始递归添加数据

问题描述 投票:0回答:2

假设我有一个看起来像这样的表(例如使用 C#):

public class Table {
    public Guid Id {get; set;}
    public string Name {get; set;}
    public Guid ParentId {get; set;}
}

这是一个递归表,其中行可以在同一个表中具有链接的父级。

假设我从头开始(即没有数据可供从其他表中选择),通过 TSQL 插入深度为 X 的新行的最佳方法是什么?

假设我希望数据看起来像这样:

此脚本的目的是进行负载测试 - 因此我没有任何可以选择的数据。数据会不断地被添加、删除和再次添加。我发现的大部分内容要么是 SELECT CTE,要么是 SELECT 之后插入。

我确信另一种选择是编写一个控制台应用程序来为我执行此操作(诚然,我的 SQL 游戏不是那么好),但我想看看是否有办法在 SQL 中执行此操作。

sql sql-server tsql common-table-expression
2个回答
2
投票

这个数据没有什么特别的(必然的)。您可以将插入脚本编写为 sql 插入语句。例如,为简单起见,此处使用

int
而不是
guid
ID 值:

create table Scratch (
    id int,
    [name] nvarchar(100),
    parentId int, 
    primary key (id))

alter table Scratch add constraint fk_temp_id 
    foreign key (parentId) references Scratch(id)

insert into Scratch (id, [Name], ParentId)
values 
    (1, 'a', null),
    (2, 'b', 1),
    (3, 'c', 1),
    (4, 'd', 2),
    (5, 'e', 2),
    (6, 'f', 3),
    (7, 'g', 3)

话虽这么说,以下是如何使用高达

N
级别深度的循环创建数据 - 但超过 63 级别将会溢出
bigint
序列值。

create table dbo.Scratch (
    id uniqueidentifier,
    [name] nvarchar(100),
    parentId uniqueidentifier, 
    seq int,
    parentSeq int,
    primary key (id));

alter table dbo.Scratch add constraint fk_temp_id 
    foreign key (parentId) references Scratch(id);

-- seed first row
insert into dbo.Scratch (id, [name], parentId, seq, parentSeq) values (newid(), '1', null, 1, null);

-- build binary tree with int ids
declare @I int = 0;
declare @J int = 0;
declare @K int;
declare @next_node bigint = 2;
while @I < 3
begin
    set @I += 1;
    set @J = 0;
    set @K = cast(power(2, @I) as bigint)
    while @J < @K / 2
    begin
        set @J += 1
        insert into dbo.Scratch(id, [name], ParentId, seq, parentSeq)
            values 
                (newid(), cast(@next_node as nvarchar(100)), null, @next_node, @next_node / 2),
                (newid(), cast(@next_node+1 as nvarchar(100)), null, @next_node+1, @next_node / 2);
        set @next_node += 2;
    end
end     

-- update the parent guids
update b
set b.parentId = a.id
from dbo.Scratch a
inner join dbo.Scratch b
on a.seq = b.ParentSeq

-- drop the temporary columns needed for creating the data
--alter table dbo.Scratch drop column parentSeq;
--alter table dbo.Scratch drop column seq;

结果:

id 名字 家长ID 序列 父序列
46b16f14-20b9-4388-a7f2-832e2c56215d 1 1
a613b692-138d-4207-8e84-43cccd0d2476 2 46b16f14-20b9-4388-a7f2-832e2c56215d 2 1
0ff8b67a-63fe-4125-b2b9-bb962d67f526 3 46b16f14-20b9-4388-a7f2-832e2c56215d 3 1
f27f82b6-d1c1-4cb2-810d-4fa21ffef5bc 4 a613b692-138d-4207-8e84-43cccd0d2476 4 2
346fd62a-6727-4414-975b-2b1659ee40c9 5 a613b692-138d-4207-8e84-43cccd0d2476 5 2
a8d3928a-6357-47ef-b1d0-0be76fa9233f 6 0ff8b67a-63fe-4125-b2b9-bb962d67f526 6 3
1c669bdf-63e1-44af-858b-752003d9a980 7 0ff8b67a-63fe-4125-b2b9-bb962d67f526 7 3
6e7ac3b1-921e-4ddc-a0c7-ad9499992689 8 f27f82b6-d1c1-4cb2-810d-4fa21ffef5bc 8 4
6786d550-7df8-4ecd-b7ca-6b7658b91b68 9 f27f82b6-d1c1-4cb2-810d-4fa21ffef5bc 9 4
d3113177-cc37-4d55-8b2d-b603345837a8 10 346fd62a-6727-4414-975b-2b1659ee40c9 10 5
bb32c1c2-9f75-455e-9aa1-fc38ddd25a6c 11 346fd62a-6727-4414-975b-2b1659ee40c9 11 5
1a218245-b6d4-41a7-8117-1b3d0bd2fdd9 12 a8d3928a-6357-47ef-b1d0-0be76fa9233f 12 6
fe8f1882-a89a-4201-83f4-b72e528ba9da 13 a8d3928a-6357-47ef-b1d0-0be76fa9233f 13 6
edab3434-c038-406e-bcf0-b6139feff6c0 14 1c669bdf-63e1-44af-858b-752003d9a980 14 7
19007b10-e86f-4fe4-9c0f-8e739f4a5c89 15 1c669bdf-63e1-44af-858b-752003d9a980 15 7

0
投票

我最终做了这样的事情(WHILE循环示例):

DECLARE @TopLevelCount BIGINT = 1
DECLARE @parentFolderId UNIQUEIDENTIFIER = NULL

WHILE @TopLevelCount < 2
BEGIN
    DECLARE @TopLevelId UNIQUEIDENTIFIER = NEWID()
    INSERT INTO Table(Id, [Name], ParentId)
    VALUES (@TopLevelId, 'Item ' + CAST(@TopLevelCount AS NVARCHAR(5)), @parentFolderId)

    DECLARE @TopLevel2Count BIGINT = @TopLevelCount * 10

    WHILE @TopLevel2Count < (@TopLevelCount * 10) + 2
    BEGIN
        DECLARE @TopLevel2Id UNIQUEIDENTIFIER = NEWID()
        INSERT INTO Table(Id, [Name], ParentId)
        VALUES (@TopLevel2Id, 'Item ' + CAST(@TopLevel2Count AS NVARCHAR(MAX)), @TopLevelId)

        DECLARE @TopLevel3Count BIGINT = @TopLevel2Count * 10

        WHILE @TopLevel3Count < (@TopLevel2Count * 10) + 2
        BEGIN
            DECLARE @TopLevel3Id UNIQUEIDENTIFIER = NEWID()
            INSERT INTO Table(Id, [Name], ParentId)
            VALUES (@TopLevel3Id, 'Item ' + CAST(@TopLevel3Count AS NVARCHAR(MAX)), @TopLevel2Id)

            DECLARE @TopLevel4Count BIGINT = @TopLevel3Count * 10

            WHILE @TopLevel4Count < (@TopLevel3Count * 10) + 2
            BEGIN
                DECLARE @TopLevel4Id UNIQUEIDENTIFIER = NEWID()
                INSERT INTO Table(Id, [Name], ParentId)
                VALUES (@TopLevel4Id, 'Item ' + CAST(@TopLevel4Count AS NVARCHAR(MAX)), @TopLevel3Id)

                DECLARE @TopLevel5Count BIGINT = @TopLevel4Count * 10

                WHILE @TopLevel5Count < (@TopLevel4Count * 10) + 2
                BEGIN
                    DECLARE @TopLevel5Id UNIQUEIDENTIFIER = NEWID()
                    INSERT INTO Table(Id, [Name], ParentId)
                    VALUES (@TopLevel5Id, 'Item ' + CAST(@TopLevel5Count AS NVARCHAR(MAX)), @TopLevel4Id)

                    DECLARE @TopLevel6Count BIGINT = @TopLevel5Count * 10

                    WHILE @TopLevel6Count < (@TopLevel5Count * 10) + 2
                    BEGIN
                        DECLARE @TopLevel6Id UNIQUEIDENTIFIER = NEWID()
                        INSERT INTO Table(Id, [Name], ParentId)
                        VALUES (@TopLevel6Id, 'Item ' + CAST(@TopLevel6Count AS NVARCHAR(MAX)), @TopLevel5Id)

                        SET @TopLevel6Count = @TopLevel6Count + 1
                    END

                    SET @TopLevel5Count = @TopLevel5Count + 1
                END

                SET @TopLevel4Count = @TopLevel4Count + 1
            END

            SET @TopLevel3Count = @TopLevel3Count + 1
        END

        SET @TopLevel2Count = @TopLevel2Count + 1
    END

    SET @TopLevelCount = @TopLevelCount + 1
END

深度为 6。我将标记 @topsail 的答案是这个问题的正确答案,因为实际上没有人可能需要这么大的深度(在我的例子中我需要 6)。

© www.soinside.com 2019 - 2024. All rights reserved.