我被赋予了一个使用游标来复制表的任务。现在说我有3个表可以复制:Company,Person_Link&人。这是一个“一对多”的关系,因为一家公司可以拥有多个人。
这是我的代码:
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
------- PersonLink Cursor ---------------------------------------------
-- Declare Variables
DECLARE @c_PeLi_PersonLinkId NVARCHAR(30)
DECLARE @c_PeLi_PersonId NVARCHAR(30)
DECLARE @c_PeLi_CompanyID NVARCHAR(30)
DECLARE @c_PeLi_CreatedBy NVARCHAR(30)
DECLARE @c_PeLi_CreatedDate NVARCHAR(30)
DECLARE @c_PeLi_UpdatedBy NVARCHAR(30)
DECLARE @c_PeLi_UpdatedDate NVARCHAR(30)
DECLARE @c_PeLi_TimeStamp NVARCHAR(30)
--Declare Cursor
DECLARE @getPeLiID CURSOR
SET @getPeLiID= CURSOR FOR
SELECT PeLi_PersonLinkId, PeLi_PersonId, PeLi_CompanyID, PeLi_CreatedBy, PeLi_CreatedDate, PeLi_UpdatedBy,
PeLi_UpdatedDate, PeLi_TimeStamp
FROM Person_Link
INNER JOIN Person
ON PeLi_PersonId = Pers_PersonId
AND PeLi_CompanyID = @comp_companyid
--Open Cursor & fetch 1st row into variables
OPEN @getPeLiID
FETCH NEXT FROM @getPeLiID INTO @c_PeLi_PersonLinkId, @c_PeLi_PersonId, @c_PeLi_CompanyID, @c_PeLi_CreatedBy,
@c_PeLi_CreatedDate, @c_PeLi_UpdatedBy, @c_PeLi_UpdatedDate, @c_PeLi_TimeStamp
--Fetch successful
--Check for a new row
WHILE @@FETCH_STATUS = 0
BEGIN
--EXEC @PersonLinkId = crm_next_id 31
INSERT INTO Person_Link
(
PeLi_PersonLinkId, PeLi_PersonId, PeLi_CompanyID, PeLi_CreatedBy, PeLi_CreatedDate, PeLi_UpdatedBy,
PeLi_UpdatedDate, PeLi_TimeStamp
)
VALUES
(
@PersonLinkId, @PersonId, @CompanyId, @c_PeLi_CreatedBy, @c_PeLi_CreatedDate, '1', GETDATE(), @c_PeLi_TimeStamp
)
--Get next available row into variables
FETCH NEXT FROM @getPeLiID INTO @c_PeLi_PersonLinkId, @c_PeLi_PersonId, @c_PeLi_CompanyID, @c_PeLi_CreatedBy,
@c_PeLi_CreatedDate, @c_PeLi_UpdatedBy, @c_PeLi_UpdatedDate, @c_PeLi_TimeStamp
END
CLOSE @getPeLiID
DEALLOCATE @getPeLiID
------- Person Cursor -------------------------------------------------
-- Declare Variables
DECLARE @c_Pers_PersonId NVARCHAR(30)
DECLARE @c_Pers_CompanyId NVARCHAR(30)
DECLARE @c_Pers_PrimaryUserId NVARCHAR(30)
DECLARE @c_Pers_FirstName NVARCHAR(30)
DECLARE @c_Pers_SecTerr NVARCHAR(30)
DECLARE @c_Pers_CreatedBy NVARCHAR(30)
DECLARE @c_Pers_CreatedDate NVARCHAR(30)
DECLARE @c_Pers_UpdatedBy NVARCHAR(30)
DECLARE @c_Pers_UpdatedDate NVARCHAR(30)
DECLARE @c_Pers_TimeStamp NVARCHAR(30)
--Declare Cursor
DECLARE @getPersID CURSOR
SET @getPersID= CURSOR FOR
SELECT Pers_PersonId, Pers_CompanyId, Pers_PrimaryUserId, Pers_FirstName, Pers_SecTerr, Pers_CreatedBy,
Pers_CreatedDate, Pers_UpdatedBy, Pers_UpdatedDate, Pers_TimeStamp
FROM Person
INNER JOIN Person_Link
ON Pers_PersonId = PeLi_PersonId
AND PeLi_CompanyID = @comp_companyid
--Open Cursor & fetch 1st row into variables
OPEN @getPersID
FETCH NEXT FROM @getPersID INTO @c_Pers_PersonId, @c_Pers_CompanyId, @c_Pers_PrimaryUserId, @c_Pers_FirstName,
@c_Pers_SecTerr, @c_Pers_CreatedBy, @c_Pers_CreatedDate, @c_Pers_UpdatedBy,
@c_Pers_UpdatedDate, @c_Pers_TimeStamp
--Fetch successful
--Check for a new row
WHILE @@FETCH_STATUS = 0
BEGIN
--EXEC @PersonId = crm_next_id 13
INSERT INTO Person
(
Pers_PersonId, Pers_CompanyId, Pers_PrimaryUserId, Pers_FirstName, Pers_SecTerr, Pers_CreatedBy,
Pers_CreatedDate, Pers_UpdatedBy, Pers_UpdatedDate, Pers_TimeStamp
)
VALUES
(
@PersonId, @companyId, @c_Pers_PrimaryUserId, @c_Pers_FirstName, @c_Pers_SecTerr, @c_Pers_CreatedBy,
@c_Pers_CreatedDate, '1', GETDATE(), @c_Pers_TimeStamp
)
--Get next available row into variables
FETCH NEXT FROM @getPersID INTO @c_Pers_PersonId, @c_Pers_CompanyId, @c_Pers_PrimaryUserId, @c_Pers_FirstName,
@c_Pers_SecTerr, @c_Pers_CreatedBy, @c_Pers_CreatedDate, @c_Pers_UpdatedBy,
@c_Pers_UpdatedDate, @c_Pers_TimeStamp
END
CLOSE @getPersID
DEALLOCATE @getPersID
这是我的表结构:
公司表:
comp_companyid | comp_primarypersonid | comp_primaryaddressid | comp_name
-------------------------------------------------------------------------
2 | 2 | 2 | company 2
3 | 3 | 3 | company 3
人员表:
pers_personid | pers_companyid | pers_primaryaddressid | pers_name
-------------------------------------------------------------------------
2 | 2 | 2 | person 2
3 | 3 | 3 | person 3
4 | 2 | 2 | person 4
人员链接表:
peli_personlinkid | peli_personid | peli_companyid
-------------------------------------------------------------------------
2 | 2 | 2
3 | 3 | 3
当只有1个人属于1家公司时,执行存储过程没有问题,但是当公司有2个人或以上时,第2个人的行不会重复,只会是第一个。
将弹出错误消息:
Msg 2627,Level 14,State 1,Procedure DuplicateCompanyInfo,Line 80
违反PRIMARY KEY约束'PK__Person_L__BCD268642CF2ADDF'。无法在对象'dbo.Person_Link'中插入重复键。消息2627,级别14,状态1,过程DuplicateCompanyInfo,第141行
违反PRIMARY KEY约束'PK__Person__381A5AC529221CFB'。无法在对象'dbo.Person'中插入重复键。
我可以通过删除评论--EXEC @PersonLinkId = crm_next_id 31
&来解决此问题。光标开始后--EXEC @PersonID = crm_next_id 13
,以便每次重复时都会生成一个新ID。但它会导致Comp_PrimaryPersonID
& Pers_PersonID
& PeLi_PersonID
没有计算,因为他们每个人都会根据他们的表复制生成自己的新ID而不是互相应用外键。
请帮助或指导我完成!在此先感谢您的时间和努力! 德斯蒙德
答案 0 :(得分:1)
抱歉,目前无法访问SQL-Server。
我无法在您插入数据的位置看到您的表定义。但是从错误看起来你的表定义不正确。即,您的主键选择对于person和person_link表不正确。您的当前主键应该是外键。
第二,为什么游标?如果你只需要将一组表中的数据复制到另一组表,为什么不只是使用查询?是否有使用光标的具体原因?
<强>更新强> 从更新的表结构中,主键和外键不明确,但看起来comp_companyid是公司表中的主键,它在Person(pers_companyid)和Person_Link(peli_companyid)表中作为外键链接。
现在,如果您的表格结构如下:
公司表: comp_companyid(PK)
人员表: pers_personid(PK)和pers_companyid(FK)
人员链接表: peli_personlinkid(PK)和peli_personid(FK),peli_companyid(FK)
除非您在PK列中插入重复项,否则我看不到任何重复问题。
现在仔细查看代码后,您将把peli_personlinkid提取到@c_PeLi_PersonLinkId变量中。
FETCH NEXT FROM @getPeLiID INTO @c_PeLi_PersonLinkId,@ c_PeLi_PersonId,@ c_PeLi_CompanyID,@ c_PeLi_CreatedBy,@ c_PeLi_CreatedDate,@ c_PeLi_UpdatedBy,@ c_PeLi_UpdatedDate,@ c_PeLi_TimeStamp
但是当您插入数据时,您没有插入此值,而是在主键中插入@PersonLinkId。由于此值来自另一个存储过程,(我不知道这个存储过程正在做什么,但看起来像生成下一个id并返回)。您在程序开始时执行的是
EXEC @PersonLinkId = crm_next_id 31
因此,在循环中,您继续为每个person_link插入此值。如果表中有多个person_link,那当然违反了PK约束。完全相同的问题也出现在Person表中。
这就是您遇到主键违规错误的原因。
不应每次都插入此值,而应插入从@c_PeLi_PersonLinkId中检索到的取值行的值。
希望这会有所帮助,您将能够解决问题。
老实说,我仍然相信你可以和你的大四学生交谈,并且在这种情况下可以很容易地避免使用游标,你可以通过简单的insert和select语句实现所有这些,并且这样做也会更好,更快。但是,如果您无法替换游标,则可以按上述标识和建议修复存储过程。