SQL 服务器:在存储过程中插入游标

SQL Server : Insert cursor within stored procedure

我是 SQL 服务器的新手,接到了一项任务,我必须使用游标复制 Phone Link table 的记录。其他 tables 我已经设法复制而不需要使用光标。但是我有 Phone Link table 的主键约束问题。有人可以帮助我吗?谢谢你。以下是我的存储过程。进气参数为comp_companyid。我的要求是将每一列复制到相同的 table 并生成新的主键和外键。

P/S:

因为我还有人 phone 和人 phone link 之后还要补充。不过我只需要先解决这个问题,然后我做人的时候可以参考这个phone.

另外,一个公司可以有多个人,地址。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[DuplicateCompanyInfo]
    @Comp_CompanyId NVARCHAR(80)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @CompanyID NVARCHAR(30),
            @PersonID NVARCHAR(30),
            @PersonLinkID NVARCHAR(30),
            @AddressLinkID NVARCHAR(30),
            @AddressID NVARCHAR(30),
            @PhoneLinkID NVARCHAR(30),
            @PhoneID NVARCHAR(30)

    EXEC @companyId = crm_next_id 5
    EXEC @PersonId = crm_next_id 13
    EXEC @PersonLinkId = crm_next_id 31
    EXEC @AddressLinkId = crm_next_id 21
    EXEC @AddressId = crm_next_id 1
    EXEC @PhoneLinkId = crm_next_id 10208
    EXEC @PhoneId = crm_next_id 14

    -- Add Company
    INSERT INTO Company
    (
        Comp_CompanyId, Comp_PrimaryPersonId, Comp_PrimaryAddressId, Comp_Name, Comp_Type, Comp_Status, Comp_CreatedBy,
        Comp_CreatedDate, Comp_UpdatedBy, Comp_UpdatedDate, Comp_TimeStamp, Comp_SecTerr, Comp_WebSite
    )
        SELECT  
            @companyId, @PersonId, @AddressId, Comp_Name, Comp_Type, 
            Comp_Status, Comp_CreatedBy,
            Comp_CreatedDate, '1', GETDATE(), Comp_TimeStamp, 
            Comp_SecTerr, Comp_WebSite
        FROM 
            Company
        WHERE 
            Comp_CompanyId = @comp_companyid

    -- Add Person_Link Without Type
    INSERT INTO Person_Link
    (
        PeLi_PersonLinkId, PeLi_PersonId, PeLi_CompanyID, PeLi_CreatedBy, PeLi_CreatedDate, PeLi_UpdatedBy,
        PeLi_UpdatedDate, PeLi_TimeStamp
    )
        SELECT 
            @PersonLinkId, @PersonId, @CompanyId, PeLi_CreatedBy, 
            PeLi_CreatedDate, '1', GETDATE(), PeLi_TimeStamp
        FROM 
            Person_Link
        WHERE 
            PeLi_CompanyID = @comp_companyid

    -- Add Person
    INSERT INTO Person
    (
        Pers_PersonId, Pers_CompanyId, Pers_PrimaryUserId, Pers_FirstName, pers_SecTerr, Pers_CreatedBy,
        Pers_CreatedDate, Pers_UpdatedBy, Pers_UpdatedDate, Pers_TimeStamp
    )
        SELECT 
            @PersonId, @companyId, Pers_PrimaryUserId, Pers_FirstName, 
            pers_SecTerr, Pers_CreatedBy,
            Pers_CreatedDate, '1', GETDATE(), Pers_TimeStamp
        FROM 
            Person
        WHERE 
            Pers_CompanyId = @comp_companyid

    -- Add Address_Link
    INSERT INTO Address_Link
    (
        AdLi_AddressLinkId, AdLi_AddressId, AdLi_CompanyID, AdLi_CreatedBy, AdLi_CreatedDate,
        AdLi_UpdatedBy, AdLi_UpdatedDate, AdLi_TimeStamp, AdLi_Type
    )
        SELECT 
            @AddressLinkId, @AddressId, @companyId, AdLi_CreatedBy, 
            AdLi_CreatedDate, '1', GETDATE(), AdLi_TimeStamp, AdLi_Type
        FROM 
            Address_Link
        WHERE  
            AdLi_CompanyID = @comp_companyid


    -- Add Address 
    INSERT INTO [Address]
    (
        Addr_AddressId, Addr_Address1, Addr_Address2, Addr_Address3, Addr_Address4, addr_postcode,
        Addr_CreatedBy, Addr_CreatedDate, Addr_UpdatedBy, Addr_UpdatedDate, Addr_TimeStamp
    )
    SELECT @AddressId, Addr_Address1, Addr_Address2, Addr_Address3, Addr_Address4, addr_postcode,
           Addr_CreatedBy, Addr_CreatedDate, '1', GETDATE(), Addr_TimeStamp
    FROM Address
    INNER JOIN Address_Link
    ON Addr_AddressId = AdLi_AddressId
    AND AdLi_CompanyID = @comp_companyid



    -- Add PhoneLink
    -- Declare Variables


    DECLARE @c_PLink_LinkID NVARCHAR(30)
    DECLARE @c_PLink_PhoneId NVARCHAR(30)
    DECLARE @c_PLink_CreatedBy NVARCHAR(30)
    DECLARE @c_PLink_CreatedDate NVARCHAR(30)
    DECLARE @c_PLink_UpdatedDate NVARCHAR(30)
    DECLARE @c_PLink_TimeStamp NVARCHAR(30)
    DECLARE @c_PLink_EntityID NVARCHAR(30)
    DECLARE @c_PLink_RecordID NVARCHAR(30)
    DECLARE @c_PLink_Type NVARCHAR(30)
    DECLARE @c_Phon_PhoneId NVARCHAR(30)

        EXEC @c_PLink_LinkID = crm_next_id 10208
        EXEC @c_PLink_PhoneId = crm_next_id 14


    --Declare Cursor
    DECLARE @getPLID CURSOR
    SET @getPLID= CURSOR FOR
    SELECT PLink_LinkID, PLink_PhoneId, PLink_CreatedBy, PLink_CreatedDate, PLink_UpdatedDate, PLink_TimeStamp,
    PLink_EntityID, PLink_RecordID, PLink_Type
    FROM PhoneLink
    WHERE PLink_EntityID = 5
    AND PLink_RecordID = @Comp_CompanyId

    --Open Cursor & fetch 1st row into variables
    OPEN @getPLID
    FETCH NEXT FROM @getPLID INTO @c_PLink_LinkID, @c_PLink_PhoneId, @c_PLink_CreatedBy,
    @c_PLink_CreatedDate, @c_PLink_UpdatedDate, @c_PLink_TimeStamp, @c_PLink_EntityID, @c_PLink_RecordID, @c_PLink_Type

    --Check for a new row
    WHILE @@FETCH_STATUS = 0
    BEGIN

        INSERT INTO PhoneLink
        (
            PLink_LinkID, PLink_PhoneId, PLink_CreatedBy, PLink_CreatedDate, PLink_UpdatedDate, PLink_TimeStamp,
            PLink_EntityID, PLink_RecordID, PLink_Type
        )

        VALUES
        (
            @c_PLink_LinkID, @c_PLink_PhoneId, @c_PLink_CreatedBy, @c_PLink_CreatedDate, @c_PLink_UpdatedDate, @c_PLink_TimeStamp,
            @c_PLink_EntityID, @c_PLink_RecordID, @c_PLink_Type
        )


    --Get next available row into variables
    FETCH NEXT FROM @getPLID INTO @c_PLink_LinkID, @c_PLink_PhoneId, @c_PLink_CreatedBy,
    @c_PLink_CreatedDate, @c_PLink_UpdatedDate, @c_PLink_TimeStamp, @c_PLink_EntityID, @c_PLink_RecordID, @c_PLink_Type

    END

    CLOSE @getPLID
    DEALLOCATE @getPLID



    -- Add Company Phone
    INSERT INTO Phone
    (
        Phon_PhoneId, Phon_Number, Phon_CreatedBy, Phon_CreatedDate, Phon_UpdatedBy, Phon_UpdatedDate, Phon_TimeStamp
    )
    SELECT @PhoneID, Phon_Number, Phon_CreatedBy, Phon_CreatedDate, '1', GETDATE(), Phon_TimeStamp
    FROM Phone
    INNER JOIN PhoneLink
    ON Phon_PhoneId = PLink_PhoneId
    AND PLink_EntityID = 5
    AND PLink_RecordID = @Comp_CompanyId


END

如果你能告诉我哪一部分做错了,我将不胜感激。提前感谢您的时间和努力!

不确定所有插入的列的含义,但如果您要插入许多行,则需要为每一行生成另一个唯一 ID。因此,您必须将 ID 生成代码移动到游标主体中,而不是将其放在游标声明之前,并在每次迭代时调用此生成器。

...
WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC @c_PLink_LinkID = crm_next_id 10208
    EXEC @c_PLink_PhoneId = crm_next_id 14

    INSERT INTO PhoneLink
    (
        PLink_LinkID, PLink_PhoneId, PLink_CreatedBy, PLink_CreatedDate, PLink_UpdatedDate, PLink_TimeStamp,
        PLink_EntityID, PLink_RecordID, PLink_Type
    )

    VALUES
    (
        @c_PLink_LinkID, @c_PLink_PhoneId, @c_PLink_CreatedBy, @c_PLink_CreatedDate, @c_PLink_UpdatedDate, @c_PLink_TimeStamp,
        @c_PLink_EntityID, @c_PLink_RecordID, @c_PLink_Type
    )


    FETCH NEXT FROM @getPLID
    INTO @c_PLink_CreatedBy, @c_PLink_CreatedDate, @c_PLink_UpdatedDate, 
      @c_PLink_TimeStamp, @c_PLink_EntityID, @c_PLink_RecordID, @c_PLink_Type
END

如果 PhoneID 也需要生成 - 您也必须将其放在光标内。 还要从游标的 select 中删除 PLink_LinkID 和 PLink_PhoneId,因为您不需要原始值。而且,当然,将它们从获取列表中删除。如上所示。

但是,
如果我的假设是正确的,那么你就走错了路。如果PhoneLink table是一个table,links一些Phone到新创建的Entity/Company,那么你需要复制Phone 首先(并为该记录生成 ID),然后 - 在新的 Phone_ID 和新的 Company_ID 之间构建一个 link。 现在,如果每个公司始终只有一个 Phone(这会有点奇怪),那么您就不需要游标。但是,如果每个公司可以有多个 phone,那么您需要生成多个新的 Phone_ID。这意味着,您需要遍历 phones and links 而不是仅遍历 links。代码应如下所示:

...
WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC @c_PLink_LinkID = crm_next_id 10208
    EXEC @c_PLink_PhoneId = crm_next_id 14

    INSERT INTO Phone
    (
      Phon_PhoneId, Phon_Number, Phon_CreatedBy, Phon_CreatedDate, Phon_UpdatedBy, Phon_UpdatedDate, Phon_TimeStamp
      )
      SELECT @PhoneID, Phon_Number, Phon_CreatedBy, Phon_CreatedDate, '1', GETDATE(), Phon_TimeStamp
      FROM Phone
      WHERE Phon_PhoneId = @Old_Phone_ID

    INSERT INTO PhoneLink
    (
        PLink_LinkID, PLink_PhoneId, PLink_CreatedBy, PLink_CreatedDate, PLink_UpdatedDate, PLink_TimeStamp,
        PLink_EntityID, PLink_RecordID, PLink_Type
    )

    VALUES
    (
        @c_PLink_LinkID, @c_PLink_PhoneId, @c_PLink_CreatedBy, @c_PLink_CreatedDate, @c_PLink_UpdatedDate, @c_PLink_TimeStamp,
        @c_PLink_EntityID, @c_PLink_RecordID, @c_PLink_Type
    )


    FETCH NEXT FROM @getPLID
    INTO @Old_Phone_ID, @c_PLink_CreatedBy, @c_PLink_CreatedDate, @c_PLink_UpdatedDate, 
      @c_PLink_TimeStamp, @c_PLink_EntityID, @c_PLink_RecordID, @c_PLink_Type
END

请注意,我已将 @Old_Phone_ID 返回到获取列表中 - 因此您可以通过 ID 找到复制的 phone。最后一个 insert-select-phone 在这种情况下不再需要(实际上在许多 phone 情况下是不正确的,因为它插入标量 @PhoneID,相同对于所有插入的行)。