LEFT OUTER JOIN导致违反唯一键约束

时间:2014-11-04 19:39:35

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

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

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

3 个答案:

答案 0 :(得分: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不同,但可以这样做。

答案 1 :(得分:0)

我要尝试的第一件事就是制作一个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是否有可能重复?

答案 2 :(得分:0)

这是一种格式化的评论。运行时会发生什么?

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