Sql server SQL Server HierarchyID:如何添加多个子项?

Sql server SQL Server HierarchyID:如何添加多个子项?,sql-server,hierarchyid,Sql Server,Hierarchyid,Izzik Ben Gan在这里描述了一些简单的方法如何处理分层数据类型 他使用存储的proc将child添加到某个根目录中 -- Web Listing 2: Script to Create Stored Procedure usp_AddEmp IF OBJECT_ID('dbo.usp_AddEmp', 'P') IS NOT NULL DROP PROC dbo.usp_AddEmp; GO CREATE PROC dbo.usp_AddEmp @empid AS INT,

Izzik Ben Gan在这里描述了一些简单的方法如何处理分层数据类型

他使用存储的proc将child添加到某个根目录中

-- Web Listing 2: Script to Create Stored Procedure usp_AddEmp
IF OBJECT_ID('dbo.usp_AddEmp', 'P') IS NOT NULL
  DROP PROC dbo.usp_AddEmp;
GO
CREATE PROC dbo.usp_AddEmp
  @empid   AS INT,
  @mgrid   AS INT = NULL,
  @empname AS VARCHAR(25),
  @salary  AS MONEY
AS

DECLARE
  @hid            AS HIERARCHYID,
  @mgr_hid        AS HIERARCHYID,
  @last_child_hid AS HIERARCHYID;

IF @mgrid IS NULL
  SET @hid = HIERARCHYID::GetRoot();
ELSE
BEGIN
  SET @mgr_hid = (SELECT hid FROM dbo.Employees WHERE empid = @mgrid);
  SET @last_child_hid =
    (SELECT MAX(hid) FROM dbo.Employees
     WHERE hid.GetAncestor(1) = @mgr_hid);
  SET @hid = @mgr_hid.GetDescendant(@last_child_hid, NULL);
END

INSERT INTO dbo.Employees(empid, hid, empname, salary)
  VALUES(@empid, @hid, @empname, @salary);
GO
要将任何叶添加到树中,需要如下调用此过程:

EXEC dbo.usp_AddEmp
  @empid =  1, @mgrid = NULL, @empname = 'David'  , @salary = $10000.00;
EXEC dbo.usp_AddEmp
  @empid =  2, @mgrid =    1, @empname = 'Eitan'  , @salary = $7000.00;
EXEC dbo.usp_AddEmp
  @empid =  3, @mgrid =    1, @empname = 'Ina'    , @salary = $7500.00;
EXEC dbo.usp_AddEmp
  @empid =  4, @mgrid =    2, @empname = 'Seraph' , @salary = $5000.00;
EXEC dbo.usp_AddEmp
  @empid =  5, @mgrid =    2, @empname = 'Jiru'   , @salary = $5500.00;
EXEC dbo.usp_AddEmp
  @empid =  6, @mgrid =    2, @empname = 'Steve'  , @salary = $4500.00;
EXEC dbo.usp_AddEmp
  @empid =  7, @mgrid =    3, @empname = 'Aaron'  , @salary = $5000.00;
EXEC dbo.usp_AddEmp
  @empid =  8, @mgrid =    5, @empname = 'Lilach' , @salary = $3500.00;
EXEC dbo.usp_AddEmp
  @empid =  9, @mgrid =    7, @empname = 'Rita'   , @salary = $3000.00;
EXEC dbo.usp_AddEmp
  @empid = 10, @mgrid =    5, @empname = 'Sean'   , @salary = $3000.00;
EXEC dbo.usp_AddEmp
  @empid = 11, @mgrid =    7, @empname = 'Gabriel', @salary = $3000.00;
EXEC dbo.usp_AddEmp
  @empid = 12, @mgrid =    9, @empname = 'Emilia' , @salary = $2000.00;
EXEC dbo.usp_AddEmp
  @empid = 13, @mgrid =    9, @empname = 'Michael', @salary = $2000.00;
EXEC dbo.usp_AddEmp
  @empid = 14, @mgrid =    9, @empname = 'Didi'   , @salary = $1500.00;
我的问题是:

我有一个表,其中列出了我需要添加到同一级别上的父级14的叶兄弟列表

declare @toadd table
 (
    empid   INT,
    mgrid   INT,
    empname VARCHAR(25),
    salary  MONEY
)

insert into @toadd(empid, mgrid, empname, salary)
select 15, 14, 'Itzik', $0.01
union all
select 16, 14, 'Jack', $0.02
union all
select 17, 14, 'Alex', $0.03
union all
select 18, 14, 'Mary', $0.04
union all
select 19, 14, 'John', $0.05
我可以创建游标并调用proc N次。
但也许可以做得更有效?以某种方式在一个查询中?

您可以使用这样一个事实,即格式为“/[int/][…n]”的字符串将正确地转换为层次ID。因此,与其使用GetDegenant将下属添加到管理器,不如获取管理器的HierarchyId,对其调用ToString,对其添加“{EmpId}/”,并将其强制转换回HierarchyId,或者如果列已经是这种类型,则只存储它。具体而言:

with emps_and_mgrs as (
   select *, m.hid as mhid
   from @toadd as t
   cross apply (
      select hid
      from dbo.Employees
      where empid= t.mgrid
   ) as m
)

INSERT INTO dbo.Employees(empid, hid, empname, salary)
select empid, mhid.ToString() + cast(empid as varchar) + '/', empname, salary
from emps_and_mgrs;

这假设每个人的hid值都是{manager's hid/empid/。这包括原始示例中的David;他的值不是GetRoot i.e./,而是/1/。同样值得注意的是,如果您要采用此策略,我还将管理器的empid存储在第行。这样,您可以编写一个递归cte,只使用empid和manager的empid来重新生成所有HieraRCHYID。你可以使用这样一个事实,即格式为“/[int/][…n]”的字符串将正确地转换为HierarchyId。因此,与其使用GetDegenant将下属添加到经理,不如使用经理的HierarchyId,调用它的字符串,再加上“{EmpId}”/'并将其强制转换回HierarchyId,或者如果列已属于此类型,则仅存储它。具体而言:

with emps_and_mgrs as (
   select *, m.hid as mhid
   from @toadd as t
   cross apply (
      select hid
      from dbo.Employees
      where empid= t.mgrid
   ) as m
)

INSERT INTO dbo.Employees(empid, hid, empname, salary)
select empid, mhid.ToString() + cast(empid as varchar) + '/', empname, salary
from emps_and_mgrs;

这假设每个人的hid值都是{manager's hid/empid/。这包括原始示例中的David;他的值不是GetRoot i.e./,而是/1/。同样值得注意的是,如果您要采用此策略,我还将管理器的empid存储在第行。这样,您可以编写一个递归cte,只使用empid和manager的empid来重新生成所有HieraRCHYID,如果有东西横行。

Thanx Ben,在我的真实数据库中,我在表中存储id、父id。但是…如果用5替换14会怎么样?例如,5已经有一些子级,需要从现有的兄弟添加这些新的5?这不是问题。因为EmpId是唯一的,所以每个相应的层次结构都是唯一的。例如EmpId=15的记录将具有层次结构/1/2/5/15/,EmpId=16将具有/1/2/5/16/。EmpId=8的预先存在的行将具有/1/2/5/8/,这与其他任何行都不同。Thanx Ben,在我的真实db I存储id中,表中的父id。但是…如果用5替换14呢?即,5已经有一些子项,需要将这些新的5添加到表中这不是问题。因为EmpId是唯一的,所以每个对应的层次结构都是唯一的。因此,例如,EmpId=15的记录将具有/1/2/5/15/层次结构,EmpId=16的记录将具有/1/2/5/16/。EmpId=8的预先存在的行将具有/1/2/5/8/,这与其他任何行都不同。