如何将一个CTE的输出添加到另一个CTE?

发布于 2025-02-05 03:51:52 字数 5364 浏览 2 评论 0原文

我有一个数据库,该数据库由8个有关员工的记录组成,它既保存了SSN,ssn是每个员工的ID,也可以保存一个引用其经理的Super_SSN。这是用于创建表的代码:

Create Table t_employee
(
    Ssn int not null,
    Super_ssn int,
    FirstName varchar(50),
    LastName varchar(50),
    NationalCode varchar(50),
    _role varchar(50),
    Primary key(Ssn),
    Foreign Key(Super_ssn) references t_employee(Ssn)
);

我必须编写Procedure,该过程需要两个员工的ID(例如,@empid1@empid2 ),然后执行以下条件的删除操作: 如果第一名员工没有任何次级员工,则将被删除。但是,如果它具有某些次数,则必须首先将它们添加到另一名员工(@empid2),然后删除。

这是我的代码:

USE CompanyHierarchy

GO

Create Procedure deleteEmployees (@empId1 int, @empId2 int)
as
Begin
    Declare @subCount int;
    With CTE1 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
    (
        Select emp.Ssn,
                emp.FirstName,
                emp.LastName,
                emp.Super_ssn,
                emp.NationalCode,
                emp._role,
                0 as _level
        From t_employee AS emp
        Where emp.Ssn = @empId1
        Union ALL
        Select _emp.Ssn,
                _emp.FirstName,
                _emp.LastName,
                _emp.Super_ssn,
                _emp.NationalCode,
                _emp._role,
                _emp._level + 1
        From t_employee _emp
        Join CTE1   C1
        on _emp.Super_ssn = C1.Ssn
    )
    Select @subCount = COUNT (*) From CTE1 c1 Where c1.Ssn <> c1.Super_ssn;
    IF @subCount = 0
    Begin
        Delete From t_employee where Ssn = @empId1;
    End

    ELSE
    Begin
         With _CTE1 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
        (
            Select emp.Ssn,
                    emp.FirstName,
                    emp.LastName,
                    emp.Super_ssn,
                    emp.NationalCode,
                    emp._role,
                    0 as _level
            From t_employee AS emp
            Where emp.Ssn = @empId1
            Union ALL
            Select _emp.Ssn,
                    _emp.FirstName,
                    _emp.LastName,
                    _emp.Super_ssn,
                    _emp.NationalCode,
                    _emp._role,
                    _emp._level + 1
            From t_employee _emp
            Join _CTE1  _C1
            on _emp.Super_ssn = _C1.Ssn
        )

        Update _CTE1 Set Super_ssn = @empId2 Where Super_ssn <> Ssn;
    End
End

GO
EXEC deleteEmployees @empId1 = 6, @empId2 = 5;

但是它显示了错误

msg 4421,第16级,状态1,过程删除员工,第37行[批次 启动行3]派生的表'_cte1'无法更新,因为列 派生表的衍生或恒定。

我还尝试实现两个cte s来选择两位员工的子和使用insert,但是我不知道如何检查不添加重复的项目。

Create Procedure deleteEmployees (@empId1 int, @empId2 int)
as
Begin
    Declare @subCount int;
    With CTE1 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
    (
        Select emp.Ssn,
                emp.FirstName,
                emp.LastName,
                emp.Super_ssn,
                emp.NationalCode,
                emp._role,
                0 as _level
        From t_employee AS emp
        Where emp.Ssn = @empId1
        Union ALL
        Select _emp.Ssn,
                _emp.FirstName,
                _emp.LastName,
                _emp.Super_ssn,
                _emp.NationalCode,
                _emp._role,
                _emp._level + 1
        From t_employee _emp
        Join CTE1   C1
        on _emp.Super_ssn = C1.Ssn
    )
    Select @subCount = COUNT (*) From CTE1 c1 Where c1.Ssn <> c1.Super_ssn;
    IF @subCount = 0
    Begin
        Delete From t_employee where Ssn = @empId1;
    End

    ELSE
    Begin
         With _CTE1 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
        (
            Select emp.Ssn,
                    emp.FirstName,
                    emp.LastName,
                    emp.Super_ssn,
                    emp.NationalCode,
                    emp._role,
                    0 as _level
            From t_employee AS emp
            Where emp.Ssn = @empId1
            Union ALL
            Select _emp.Ssn,
                    _emp.FirstName,
                    _emp.LastName,
                    _emp.Super_ssn,
                    _emp.NationalCode,
                    _emp._role,
                    _emp._level + 1
            From t_employee _emp
            Join _CTE1  _C1
            on _emp.Super_ssn = _C1.Ssn
        )
        , _CTE2 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
        (
            Select emp.Ssn,
                    emp.FirstName,
                    emp.LastName,
                    emp.Super_ssn,
                    emp.NationalCode,
                    emp._role,
                    0 as _level
            From t_employee AS emp
            Where emp.Ssn = @empId1
            Union ALL
            Select _emp.Ssn,
                    _emp.FirstName,
                    _emp.LastName,
                    _emp.Super_ssn,
                    _emp.NationalCode,
                    _emp._role,
                    _emp._level + 1
            From t_employee _emp
            Join _CTE2  _C2
            on _emp.Super_ssn = _C2.Ssn
        )
        Insert Into _CTE2
        Select * From _CTE1;
    End
End

我将感谢您的帮助。

I have a database that consists of 8 records about the employees, and it saves both the Ssn which is the id of every employee and a Super_ssn that references their manager. Here is the code for creating the table:

Create Table t_employee
(
    Ssn int not null,
    Super_ssn int,
    FirstName varchar(50),
    LastName varchar(50),
    NationalCode varchar(50),
    _role varchar(50),
    Primary key(Ssn),
    Foreign Key(Super_ssn) references t_employee(Ssn)
);

I have to write a Procedure which takes two employees' id, (for example, @empId1 and @empId2), and then perform the delete operation, with the below condition:
If the first employee did not have any subalterns, it would be deleted. But if it had some subalterns, they must first be added to another employee (@empId2) and then deleted.

Here is my code:

USE CompanyHierarchy

GO

Create Procedure deleteEmployees (@empId1 int, @empId2 int)
as
Begin
    Declare @subCount int;
    With CTE1 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
    (
        Select emp.Ssn,
                emp.FirstName,
                emp.LastName,
                emp.Super_ssn,
                emp.NationalCode,
                emp._role,
                0 as _level
        From t_employee AS emp
        Where emp.Ssn = @empId1
        Union ALL
        Select _emp.Ssn,
                _emp.FirstName,
                _emp.LastName,
                _emp.Super_ssn,
                _emp.NationalCode,
                _emp._role,
                _emp._level + 1
        From t_employee _emp
        Join CTE1   C1
        on _emp.Super_ssn = C1.Ssn
    )
    Select @subCount = COUNT (*) From CTE1 c1 Where c1.Ssn <> c1.Super_ssn;
    IF @subCount = 0
    Begin
        Delete From t_employee where Ssn = @empId1;
    End

    ELSE
    Begin
         With _CTE1 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
        (
            Select emp.Ssn,
                    emp.FirstName,
                    emp.LastName,
                    emp.Super_ssn,
                    emp.NationalCode,
                    emp._role,
                    0 as _level
            From t_employee AS emp
            Where emp.Ssn = @empId1
            Union ALL
            Select _emp.Ssn,
                    _emp.FirstName,
                    _emp.LastName,
                    _emp.Super_ssn,
                    _emp.NationalCode,
                    _emp._role,
                    _emp._level + 1
            From t_employee _emp
            Join _CTE1  _C1
            on _emp.Super_ssn = _C1.Ssn
        )

        Update _CTE1 Set Super_ssn = @empId2 Where Super_ssn <> Ssn;
    End
End

GO
EXEC deleteEmployees @empId1 = 6, @empId2 = 5;

But it shows the error that

Msg 4421, Level 16, State 1, Procedure deleteEmployees, Line 37 [Batch
Start Line 3] Derived table '_CTE1' is not updatable because a column
of the derived table is derived or constant.

I have also tried to implement two CTEs to select the subalterns of both employees, and the use INSERT, but I do not know how to check not to add duplicate items.

Create Procedure deleteEmployees (@empId1 int, @empId2 int)
as
Begin
    Declare @subCount int;
    With CTE1 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
    (
        Select emp.Ssn,
                emp.FirstName,
                emp.LastName,
                emp.Super_ssn,
                emp.NationalCode,
                emp._role,
                0 as _level
        From t_employee AS emp
        Where emp.Ssn = @empId1
        Union ALL
        Select _emp.Ssn,
                _emp.FirstName,
                _emp.LastName,
                _emp.Super_ssn,
                _emp.NationalCode,
                _emp._role,
                _emp._level + 1
        From t_employee _emp
        Join CTE1   C1
        on _emp.Super_ssn = C1.Ssn
    )
    Select @subCount = COUNT (*) From CTE1 c1 Where c1.Ssn <> c1.Super_ssn;
    IF @subCount = 0
    Begin
        Delete From t_employee where Ssn = @empId1;
    End

    ELSE
    Begin
         With _CTE1 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
        (
            Select emp.Ssn,
                    emp.FirstName,
                    emp.LastName,
                    emp.Super_ssn,
                    emp.NationalCode,
                    emp._role,
                    0 as _level
            From t_employee AS emp
            Where emp.Ssn = @empId1
            Union ALL
            Select _emp.Ssn,
                    _emp.FirstName,
                    _emp.LastName,
                    _emp.Super_ssn,
                    _emp.NationalCode,
                    _emp._role,
                    _emp._level + 1
            From t_employee _emp
            Join _CTE1  _C1
            on _emp.Super_ssn = _C1.Ssn
        )
        , _CTE2 (Ssn, FirstName, LastName, Super_ssn, NationalCode, _role, _level) as
        (
            Select emp.Ssn,
                    emp.FirstName,
                    emp.LastName,
                    emp.Super_ssn,
                    emp.NationalCode,
                    emp._role,
                    0 as _level
            From t_employee AS emp
            Where emp.Ssn = @empId1
            Union ALL
            Select _emp.Ssn,
                    _emp.FirstName,
                    _emp.LastName,
                    _emp.Super_ssn,
                    _emp.NationalCode,
                    _emp._role,
                    _emp._level + 1
            From t_employee _emp
            Join _CTE2  _C2
            on _emp.Super_ssn = _C2.Ssn
        )
        Insert Into _CTE2
        Select * From _CTE1;
    End
End

I will be grateful for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风铃鹿 2025-02-12 03:51:52

您是否使您的代码过度复杂化?您为什么根本穿越层次结构?当然,如果您打算在“ b”报告“ A”和“ C”向“ B”报告时删除“ A”,则您不打算对“ C”做任何事情。您只需要将这些报告直接更改为“ A”(在这种情况下)。如果是这样,则不需要CTE即可穿越层次结构。您还学会了不良习惯,并选择了奇怪的命名标准。

只需检查是否存在@empid1(一个通用名称,该名称不提供有关其使用方式的任何线索 - 请先作为主管作为主管,而不是“移动”(不是Move”(不是“添加”)将这些行到其他用户参数@Empid2。简而言之:

update t_employee set Super_ssn = @empId2
where Super_ssn = @empId1;

delete t_employee where Ssn = @empId1;

这就是您在非常基本的层面上需要的所有代码。添加您想要的任何错误处理,也许是对参数值进行的一些理智检查,也许可以在更新之前检查存在。使用两个零件名称(schema.table)是开发的最佳实践。

Have you overcomplicated your code? Why do you traverse the hierarchy at all? Surely if you intend to delete "a" when "b" reports to "a" and "c" reports to "b", you don't intend to do anything to "c". You only need to change those reporting directly to "a" ("b" in this case). If so, you don't need CTEs to traverse the hierarchy. You have also learned bad habits and have chosen strange naming standards.

Just check for the existence of @empId1 (a generic name that does not provide any clues about how it is used - see what I mean by naming standards?) as a supervisor first and "move" (not "add") those rows to the other user parameter @empId2. In short:

update t_employee set Super_ssn = @empId2
where Super_ssn = @empId1;

delete t_employee where Ssn = @empId1;

That is all the code you need at a very basic level. Add whatever error handling you wish, perhaps some sanity checking of the parameter values, and perhaps check for existence before the update. Use of two part names (schema.table) is a best practice to develop.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文