【问题标题】:LEFT OUTER JOIN causing violation of unique key constraintLEFT OUTER JOIN 导致违反唯一键约束
【发布时间】:2014-11-04 19:39:35
【问题描述】:

我有两个公司的两个数据库在同一个软件上运行,因此数据库结构是相同的。

Windows Server 2003、MS SQL Sever 2005。

我正在尝试将项目列表和相关表格从 SOURCE 复制到 DESTINATION。

总共有 11 个表,我使用相同格式的脚本来完成所有 11 个表的工作。其中三个失败了。

下面的例子是三个之一:

--dbo.ITEM_MEASURE 5
SET IDENTITY_INSERT DESTINATION.dbo.ITEM_MEASURE ON

INSERT DESTINATION.dbo.ITEM_MEASURE(
  ITEM_MEASURE_ID, MEAS_TYPE, ITEMNO, MEAS_CODE, SELLPRIC, MARKUP, S_PERC_DOC, 
  MIN_AMOUNT, COSTPERSP, COST, COST_LOW, COST_HIGH, WEIGHT_MEAS, WEIGHT,
  SIZE_MEAS, LENGTH, BREADTH, HEIGHT, VOLUME_MEAS, VOLUME, LAST_COST)
SELECT s.ITEM_MEASURE_ID, s.MEAS_TYPE, s.ITEMNO, s.MEAS_CODE, s.SELLPRIC,
  s.MARKUP, s.S_PERC_DOC, s.MIN_AMOUNT, s.COSTPERSP, '0', '0', '0' ,
  s.WEIGHT_MEAS, s.WEIGHT, s.SIZE_MEAS, s.LENGTH, s.BREADTH, s.HEIGHT,
  s.VOLUME_MEAS, s.VOLUME, '0'
FROM SOURCE.dbo.ITEM_MEASURE s
  LEFT OUTER JOIN DESTINATION.dbo.ITEM_MEASURE d
    ON (d.ITEM_MEASURE_ID = s.ITEM_MEASURE_ID)
WHERE d.ITEM_MEASURE_ID IS NULL

SET IDENTITY_INSERT DESTINATION.dbo.ITEM_MEASURE OFF

/* ERROR
Msg 2627, Level 14, State 1, Line 73
Violation of UNIQUE KEY constraint 'IN_ITEM_MEASURE_UQ_ITEM_TYPE_MEAS'. Cannot insert duplicate key in object 'dbo.ITEM_MEASURE'.
The statement has been terminated.
*/

表 PK 是 ITEM_MEASURE_ID,分别在 SOURCE 或 DESTINATION 中没有重复项,据我了解,“WHERE d.ITEM_MEASURE_ID IS NULL”语句阻止它尝试将数据复制到已经存在的 DESTINATION。

为什么会出现此错误?

更新 - 无法发布图片,但请查看约束和索引。:
https://photos-6.dropbox.com/t/1/AAD2EzrJTZFy_BMqcL5i2dWmZn1bAp5C7Y6LAHwJZ1btYQ/12/1501690/png/1024x768/3/1415138400/0/2/constraint.png/vvHTaOuDXOO72MN7IYeDnbLzAjQ65deom5zF9GV3jgw

更新 - IN_ITEM_MEASURE_UQ_ITEM_TYPE_MEASURE 的属性:https://photos-3.dropbox.com/t/1/AAC8eurM2o8SfHfvLNOsvwt8h_2P_qGpvRBmhovIp3cJzg/12/1501690/png/1024x768/3/1415142000/0/2/properties.PNG/Lf4Q_hE1QTsHgEI1BAxR9WoyL2R71MPFxDZJ5R9kXN0

【问题讨论】:

  • UNIQUE KEY约束'IN_ITEM_MEASURE_UQ_ITEM_TYPE_MEAS'的定义是什么?
  • 请回答@DeanOC 的问题,因为最可能的问题是除了主键之外还有另一个唯一键
  • 很抱歉报告,我不明白这个问题,也不知道如何回答。我对 SQL 很熟悉,这是我第一次尝试理解这些东西。
  • 根据 dbo.ITEM_MEASURE 的设计,唯一显示的关键是 PK
  • @todbanner 但是错误信息清楚地写着:UNIQUE KEY constraint 'IN_ITEM_MEASURE_UQ_ITEM_TYPE_MEAS'。因此,转到表的索引,看看那里是否有唯一索引。或约束

标签: sql sql-server outer-join unique-key surrogate-key


【解决方案1】:

除了 PK 之外,受影响的表(可能还有其他表)似乎最有可能具有一个或多个 UNIQUE 约束(或唯一索引)。例如,违反约束的名称表明它可能是一个约束,例如

UNIQUE(ITEMNO, MEAS_TYPE)

... 或此类列集合上的唯一索引。没有特别的理由假设在两个不相关的数据库中,相等的 (ITEMNO, MEAS_TYPE) 对(或任何其他非 PK 数据)将与相同的 PK 相关联,因此您避免 PK 违规的策略不一定能避免违规像这样的约束。

就此而言,您没有提出任何理由相信您的源表和目标表中的 PK 以任何方式相关。尽管它可能使表复制继续进行而不会出错,但我认为没有理由相信您提供的查询实际上是在做正确的事情。

编辑添加: 事实上,ITEM_MEASURE_ID 看起来像是一个代理键(即由应用程序或 DBMS 发明的,独立于任何数据)。通过这样的键将源数据与独立记录的目标数据相匹配是极不可能给您带来有意义的结果的(在其他表中也不)。如果确实合适,您应该使用自然键,例如 (ITEMNO, MEAS_TYPE)。在您的表中有UNIQUE 约束或唯一索引的地方,它们可以作为自然键的线索。对于这个单独的表,它可能看起来像这样:

-- NOTE: NOT inserting values for the IDENTITY column

INSERT DESTINATION.dbo.ITEM_MEASURE(
  MEAS_TYPE, ITEMNO, MEAS_CODE, SELLPRIC, MARKUP, S_PERC_DOC, 
  MIN_AMOUNT, COSTPERSP, COST, COST_LOW, COST_HIGH, WEIGHT_MEAS, WEIGHT,
  SIZE_MEAS, LENGTH, BREADTH, HEIGHT, VOLUME_MEAS, VOLUME, LAST_COST)
SELECT s.MEAS_TYPE, s.ITEMNO, s.MEAS_CODE, s.SELLPRIC,
  s.MARKUP, s.S_PERC_DOC, s.MIN_AMOUNT, s.COSTPERSP, '0', '0', '0' ,
  s.WEIGHT_MEAS, s.WEIGHT, s.SIZE_MEAS, s.LENGTH, s.BREADTH, s.HEIGHT,
  s.VOLUME_MEAS, s.VOLUME, '0'
FROM SOURCE.dbo.ITEM_MEASURE s
  LEFT OUTER JOIN DESTINATION.dbo.ITEM_MEASURE d
    ON (d.ITEMNO = s.ITEMNO) AND (d.MEAS_TYPE = s.MEAS_TYPE)
WHERE d.ITEMNO IS NULL

如果您需要处理相关的源表,这会变得更加混乱,因为目标表中的 PK 与源表中的 PK 不同,但可以做到。

【讨论】:

  • 我想我明白你在说什么,你不确定执行此操作会产生预期的效果。正如我在问题中所说,这是我正在复制的十一个表之一,十一个表中有八个执行没有错误。一旦我拥有了所有 11 个,这将导致两个公司数据库中的项目列表被同步。
  • 如果两家公司的表PK不相关,那么你的查询结果是垃圾,不是同步表。也就是说,在两个表中出现相同 PK 的情况下,如果该行的其余部分可能因一个表与另一个表不同,那么您的方法是不正确的。在这种情况下,您遇到的约束违规是一个幸运的警告,试图提示您解决方法中的问题。
  • 我来看看这两个表中的数据。理论上,目前 DESTINATION 中的所有部件号都与 SOURCE 中的相同。因此,对于同时存在于两者中的记录,ITEM_MEASURE_ID 在 SOURCE 和 DESTINATION 中应该是相同的。我现在会仔细检查一下。
  • ITEM_MEASURE_IDs 的相关性不会因为对其他列使用相同的值空间(可能是 ITEMNO?)而得出。事实上,如果这些 ID 是自动分配的,那么它们之间就不太可能相互关联,因为这需要以相同的顺序将相等的记录插入到每个表中。
  • 我已经编辑了我的答案以添加一个可能的解决方案,适用于单表。正如我在那里指出的那样,我认为这个问题可能比您所考虑的要复杂得多。
【解决方案2】:

我会尝试的第一件事是创建一个 select 语句来查看冲突是什么。

SELECT * FROM DESTINATION.dbo.ITEM_MEASURE
WHERE ITEM_MEASURE_ID IN (SELECT s.ITEM_MEASURE_ID FROM SOURCE.dbo.ITEM_MEASURE s
 LEFT OUTER JOIN DESTINATION.dbo.ITEM_MEASURE d ON (d.ITEM_MEASURE_ID = s.ITEM_MEASURE_ID)
WHERE d.ITEM_MEASURE_ID IS NULL)

这应该告诉你什么是冲突的。除此之外,DESTINATION.dbo.ITEM_MEASURE 是否有重复项?

【讨论】:

  • 问题已经指定两个表中没有重复项。
  • 您在上面建议的查询没有返回任何内容。但是,如果我并排打开这两个表,SOURCE 中有 1200 多条记录应该被复制到 DESTINATION。我在 excel 中打开了两个表,对重复项进行了排序和删除。两者都导致无重复。所以我相信这已经排除了。
【解决方案3】:

这是一个格式化的评论。当你运行它时会发生什么?

select item_measure_id, count(*) records
from (SELECT s.ITEM_MEASURE_ID, s.MEAS_TYPE, s.ITEMNO, s.MEAS_CODE, s.SELLPRIC,
s.MARKUP, s.S_PERC_DOC, s.MIN_AMOUNT, s.COSTPERSP, '0', '0', '0' ,
s.WEIGHT_MEAS, s.WEIGHT, s.SIZE_MEAS, s.LENGTH, s.BREADTH, s.HEIGHT,
s.VOLUME_MEAS, s.VOLUME, '0'
FROM SOURCE.dbo.ITEM_MEASURE s
LEFT OUTER JOIN DESTINATION.dbo.ITEM_MEASURE d
ON (d.ITEM_MEASURE_ID = s.ITEM_MEASURE_ID)
WHERE d.ITEM_MEASURE_ID IS NULL
) temp
group by item_measure_id
having records > 1
order by records desc

【讨论】:

  • Msg 8155, Level 16, State 2, Line 21 没有为“temp”的第 10 列指定列。消息 8155,级别 16,状态 2,第 21 行没有为“temp”的第 11 列指定列。消息 8155,级别 16,状态 2,第 21 行没有为“temp”的第 12 列指定列。消息 8155,级别 16,状态 2,第 21 行没有为“temp”的第 21 列指定列。消息 207,级别 16,状态 1,第 31 行无效的列名称“记录”。
  • 糟糕,错过了 group by 子句。
  • 你想让我运行一些不同的东西吗?
猜你喜欢
  • 1970-01-01
  • 2019-10-07
  • 2014-02-23
  • 2019-05-03
  • 2020-04-01
  • 2012-05-28
  • 1970-01-01
  • 2015-12-17
  • 2011-05-25
相关资源
最近更新 更多