【问题标题】:SQL Server : Insert cursor within stored procedureSQL Server:在存储过程中插入游标
【发布时间】:2016-04-11 01:54:34
【问题描述】:

我是 SQL Server 的新手,我接到了一项任务,我必须使用游标来复制电话链接表的记录。我设法复制的其他表不需要使用游标。但是我有电话链接表的主键约束问题。有人会帮助我吗?谢谢你。以下是我的存储过程。摄入参数是comp_companyid。我的要求是将每一列复制到同一个表中并生成新的主键和外键。

P/S:

  • EntityID = 5(公司)
  • EntityID = 13(人)

因为我有个人电话和个人电话链接,之后也可以添加。但是我只需要先解决这个问题,然后我在做个人电话时可以参考这个。

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

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

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

【问题讨论】:

  • PhoneLink 表的主键是什么?
  • @Dan 这是 PLink_LinkID
  • 为什么所有的id都是varchar?
  • @Ivan 我正在关注我前辈的样本。他也将所有 ID 声明为 NVARCHAR。我相信不会有太大影响吧?
  • @DesmondChau,我没有看到为新行生成新的 PLink_LinkID 值的代码,所以当然,在从现有行复制值时,您总是会遇到 PK 冲突。您通常如何为新行生成 PLink_LinkID 值?如果是SEQUENCE,你也需要在这里使用它。

标签: sql sql-server stored-procedures cursor


【解决方案1】:

不确定所有插入的列的含义,但如果您要插入许多行,则需要为每行生成另一个唯一 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 - 您也必须将其放在光标内。 还要从光标的选择中删除 PLink_LinkID 和 PLink_PhoneId ,因为您不需要原始值。当然,从获取列表中删除它们。如上所示。

但是,
如果我的假设是正确的,那么您将走错路。如果PhoneLink 表是将一些电话链接到新创建的实体/公司的表,那么您需要先复制电话(并为该记录生成 ID),然后 - 建立新电话 ID 和新公司 ID 之间的链接。 现在,如果您总是每个公司只有一部电话(这会有点奇怪),那么您不需要光标。但是,如果每个公司可以有几部电话,那么您需要生成几个新的 Phone_ID。这意味着,您需要遍历电话 链接,而不是仅迭代链接。代码应该是这样的:

...
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 找到复制的电话。在这种情况下不再需要最后一个 insert-select-phone(实际上在许多手机情况下是不正确的,因为它插入标量 @PhoneID,对于所有插入的行都相同)。

【讨论】:

  • Ivan,非常感谢您的努力!但我想知道如何声明 @Old_PhoneID 以便它采用旧值的值?
  • 光标选择语句中的PLink_PhoneId
  • INSERT INTO Phone 部分,WHERE PhoneID=@Old_Phone_ID,你是说WHERE Phon_PhoneID=@Old_Phone_ID 吗?而且我不能在没有正确声明的情况下将 @Old_Phone_ID 放入其中。
  • 是的,就是Phone_phone_id。稍后会修复 - 现在用我的手机写信。
  • 我已经为你编辑了。你能告诉我如何声明@Old_Phone_ID 以及我应该将它声明为什么?抱歉,我是 SQL 新手,可能会问一些明显的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-03
  • 1970-01-01
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 2010-09-06
相关资源
最近更新 更多