【问题标题】:DTS Package Terminates because of Duplicate Key RowDTS 包因重复键行而终止
【发布时间】:2013-10-07 20:39:13
【问题描述】:

我们有一个旧的 DTS 包,我们的 SQL 2000 Server 使用它来将员工记录推送到我们制造车间的机器上。

最近,我们升级了其中一台机器,现在它正在运行 SQL 2008 Express。

我们已重新配置 DTS 包以将员工记录推送到此新服务器,但现在我们收到以下错误消息:

FETCH_EMPLOYEES:

语句已终止。无法在具有唯一索引“IX_tblUsers_OpID”的对象“dbo.Users”中插入重复的键行。

如果我远程访问我们的 SQL 2000 服务器,我可以右键单击以连续执行 DTS 包的每个步骤,而不会出现错误。

所以,我登录到这台机器的 SQL 2008 Express 实例,看看我能不能搞清楚。

现在我正在查看 FETCH_EMPLOYEES 存储过程:

PROCEDURE [dbo].[FETCH_EMPLOYEES] AS
DECLARE @OpID varchar(255)
DECLARE @Password varchar(50)
DECLARE Employee_Cursor CURSOR FOR
SELECT OpID, Password
FROM dbo.vw_Employees
OPEN Employee_Cursor
FETCH NEXT FROM Employee_Cursor
INTO @OpID,@Password
WHILE @@FETCH_STATUS = 0
BEGIN
insert into dbo.Users (OpID,Password,GroupID) 
VALUES (@OpID,@Password,'GROUP01')
FETCH NEXT FROM Employee_Cursor
INTO @OpID,@Password
END
CLOSE Employee_Cursor
DEALLOCATE Employee_Cursor

我不太了解游标,但我可以看出数据是从名为 vw_Employees 的视图中提取的,并被插入到表 dbo.Users 中。

vw_Employees 的视图很简单:

SELECT DISTINCT FirstName + ' ' + LastName AS OpID, Num AS Password
FROM         dbo.EmployeeInfo
WHERE     (Num IS NOT NULL) AND (FirstName IS NOT NULL)
      AND (LastName IS NOT NULL) AND (Train IS NULL OR Train <> 'EX')

所以,现在看来问题一定出在表dbo.Users

我没有看到任何特别关注的内容,因此我使用CREATE TO Query Editor 编写了此表并得到了我不太了解的信息:

CREATE TABLE [dbo].[Users](
[ID] [int] IDENTITY(1,1) NOT NULL,
[OpID] [nvarchar](255) NOT NULL,
[Password] [nvarchar](50) NOT NULL,
[GroupID] [nvarchar](10) NOT NULL,
[IsLocked] [bit] NOT NULL,
    CONSTRAINT [PK_tblUsers] PRIMARY KEY CLUSTERED 
(
[ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Users]  WITH CHECK ADD  CONSTRAINT [FK_tblUsers_tblGroups] FOREIGN KEY([GroupID])
REFERENCES [dbo].[Groups] ([GroupID])
GO

ALTER TABLE [dbo].[Users] CHECK CONSTRAINT [FK_tblUsers_tblGroups]
GO

ALTER TABLE [dbo].[Users] ADD  CONSTRAINT [DF_tblUsers_IsLocked]  DEFAULT ((0)) FOR [IsLocked]
GO

好的,我觉得问题出在这个表定义的某个地方,但我不太明白它在做什么(在创建基本表之后)。

它有一个包含很多我不理解的变量的 CONSTRAINT 部分,然后它正在更改这些表以添加 FOREIGN KEY 和 CONSTRAINTS。

我的问题:有人能帮我理解错误告诉我什么(除了一些重复的密钥违规)。

哪一列可能引发重复键违规?

我是否包含足够的数据和屏幕截图?

更新:

根据评论,听起来需要这张截图。

Users 表中,有一个索引列表,其中一个名为 IX_tblUsers_OpID 的索引表示它是唯一且非集群的。

我认为我们已经消除了源数据表 EmployeeInfo 上重复的 Op_ID 值,方法是使用此脚本查找所有这些值:

select num as 'Op_ID', count(num) as 'Occurrences'
from employeeInfo
group by num
having 1<count(num);

应该已经摆脱了我所有的重复。对吧?

我们购买的制造机器配备了用于存储本地数据的 PC。他们提供了我发布的这些脚本,所以我无法评论他们为什么选择他们所做的事情。我们只是运行一个将数据拉到我们的服务器上的作业。

【问题讨论】:

  • 感谢您尝试提供详细信息。在您的第一个屏幕截图中,错误表明插入与唯一索引 IX_tblUsers_OPID 冲突。在上面的脚本中,我没有看到该索引。你有没有可能从错误的位置编写脚本?
  • 仅仅因为唯一索引的名称 (IX_tblUsers_OpID),它似乎在列 OpID 上(尽管这对我来说似乎不正确)。无论如何,您可以发布该索引定义吗?另一方面,您的 sp 似乎并没有检查该表上行的存在,它只是将它们全部插入(我也看不出有任何理由在那里使用游标)
  • 现在对问题进行了更新,其中包含Indexes 的新屏幕截图,其中包括一个名为IX_btlUsers_OpID 的屏幕截图。制造公司为他们的机器提供已有的数据库和脚本。我们只是尝试将旧的 DTS 包插入这些新机器。
  • 但是根据您的 sp,opID 的值来自视图,它们由以下组成:FirstName + ' ' + LastName,而不是 num
  • 看起来是这样,是的。但是,正如我之前在评论中所说,我看不到您在INSERT 之前检查表上是否存在行(或者您总是先删除该表?)。您可能正在尝试插入已经存在的行

标签: sql-server sql-server-2008 dts


【解决方案1】:

拥有具有唯一值的列在任何数据集上始终具有很高的价值。可以将此约束添加到任何列或索引。

您收到的错误非常明确且非常具体。它确实给出了答案。

语句已终止。无法在具有唯一索引“IX_tblUsers_OpID”的对象“dbo.Users”中插入重复的键行。

它说“没有重复......唯一索引......”然后它告诉您约束的名称“IX_tblUsers_OpID”。

现在请记住,您正在尝试通过连接两个字符串来在该列中插入您即时制作的值;姓名,加上姓氏。

想出其中两个是“约翰·史密斯”的机会有多大?高,非常高!

可能的解决方案:

  • 您可以删除约束并允许重复。
  • 修改查询,使尝试插入的值是-确实-唯一的。
  • 使用“WITH (IGNORE_DUP_KEY = ON)”参考:index_option (Transact-SQL)

【讨论】:

  • 这是一个很好的答案。我明白你的意思。在我们工厂制造机器的制造商将我们数据库的员工姓名映射到他们的 OpID 字段,将我们的员工编号映射到他们的密码字段。该数据可以追溯到 2004 年左右。更改每台机器将涉及将它们送回制造商进行重新配置。这些是用于空调线圈的旧真空室,价值 1000 万美元。它可能永远不会发生。 :)
  • 我建议您通过修改您的视图 [vw_Employees] 来遵循选项 2。将员工 ID 添加到名称:FirstName + ' ' + LastName + CAST(num AS VARCHAR(10)) AS OpID。或者只是在同一个视图中使用“num as OpID”。
  • 等等...您应该可以自己更改该视图而无需将其发送给制造商...不是吗?
  • 你知道那些说你不能篡改其他公司的软件的条款吗?他们有来自同一家公司的 10 台机器。他们中的任何一个都被篡改了,他们拒绝对他们进行任何工作。不过,这是一个老问题。我得到它是为了让我的软件可以防止重复的 John Smith 名字(John Smith1 等)。
  • 啊哈!我懂了。无论如何,我很高兴你找到了解决方案。 =)
【解决方案2】:

工作中的另一个人发现了这个隐藏的功能,它解决了眼前的问题,但可能会导致其他未知问题。

Users 表设计器视图中,我们可以右键单击OpID 列,选择Indexes/Keys...,找到这个创建的IX_tblUsers_OpID 键并将其更改为是唯一的值:

这似乎是为了让 DTS 包运行,这就是我们现在正在做的事情。

我回到 SQL 2000 服务器上的原始 EmployeeInfo 表,使用此脚本检查重复的 OpID 值:

select FirstName + ' ' + LastName as 'OpID',
       Count(FirstName + ' ' + LastName) as 'Occurrences'
from EmployeeInfo
group by FirstName + ' ' + LastName
having 1 < count(FirstName + ' ' + LastName)

...但没有返回任何记录。

我不知道为什么 DTS 包失败或为什么我们必须关闭唯一功能。

如果有人在以后的某个时间提出了更好的解决方案,请发布!

【讨论】:

    猜你喜欢
    • 2021-08-05
    • 2020-05-18
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    • 2018-09-06
    • 2014-08-29
    相关资源
    最近更新 更多