如何制定 T-SQL 以避免主键约束?

Posted

技术标签:

【中文标题】如何制定 T-SQL 以避免主键约束?【英文标题】:How to formulate T-SQL to avoid a primary key constraint? 【发布时间】:2010-08-24 15:20:56 【问题描述】:

我正在尝试开发一个查询来仅返回非重复记录,以便我可以将这些记录添加到我的数据库中,但我不断收到此错误:

消息 2627,第 14 级,状态 1,第 1 行 违反主键约束“PK_j5c_MasterMeasures”。 无法在对象“dbo.j5c_MasterMeasures”中插入重复键。 声明已终止。

这是我正在使用的最新查询:

CREATE TABLE #GOOD_RECORDS3 (STUDENTID VARCHAR(50), MEASUREDATE SMALLDATETIME, 
measurename VARCHAR(100), LabelName VARCHAR(100), score_10 VARCHAR(100))
INSERT INTO #GOOD_RECORDS3
select A.studentid, A.measuredate, B.measurename, B.LabelName, A.score_10 
from [J5C_Measures_Sys] A join [J5C_ListBoxMeasures_Sys] B on 
A.MeasureID = B.MeasureID
where score_10 is not null and score_10 <> '0' 
except
select A.studentid, A.measuredate, B.measurename, B.LabelName, A.score_10
from [J5C_Measures_Sys] A join [J5C_ListBoxMeasures_Sys] B on 
A.MeasureID = B.MeasureID
where score_10 is not null and score_10 <> '0'
GROUP BY A.studentid, A.measuredate, B.measurename, B.LabelName, A.score_10
having COUNT(A.score_10) > 1

delete #GOOD_RECORDS3
from #GOOD_RECORDS3 a
join sysobjects so on so.name = 'J5C_Measures_Sys' AND so.type = 'u'
join syscolumns sc on so.id = sc.id and sc.name = 'score_10'
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name
WHERE A.SCORE_10 IS NOT NULL AND A.STUDENTID IS NOT NULL AND 
A.MEASUREID IS NOT NULL
and exists (select 1 from J5C_MasterMeasures M
 where M.StudentID = A.StudentID
and M.MeasureID = A.MeasureID)

Insert into J5C_MasterMeasures (studentid, measuredate, measureid, nce)
select A.studentid, A.measuredate, a.MEASUREID, A.score_10
from #GOOD_RECORDS3 a
join sysobjects so on so.name = 'J5C_Measures_Sys' AND so.type = 'u'
join syscolumns sc on so.id = sc.id and sc.name = 'score_10'
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name
WHERE A.SCORE_10 IS NOT NULL AND A.STUDENTID IS NOT NULL AND 
A.MEASUREID IS NOT NULL

令人困惑的部分是 M5C_Measures_Sys 中的 MeasureId = B.measurename + ' ' + B.Labelname。这是来自#GOOD_RECORDS3的一些示例数据:

1   2006-03-01 00:00:00 ISAT Reading ISAT Reading   564
10005   2003-11-17 00:00:00 TerraNova Reading TerraNova Reading     19
10005   2003-11-17 00:00:00 TerraNova Science TerraNova Science     26
10005   2003-11-17 00:00:00 TerraNova Total Battery TerraNova Total Battery     22
10005   2003-11-17 00:00:00 TerraNova Total Language TerraNova Total Language   43

所以你可以看到b.measurename = b.labelname。上面的错误发生在插入。

您的回答查询结果如下:

1   2006-03-01 00:00:00 ISAT Reading    ISAT Reading    564
10005   2003-11-17 00:00:00 TerraNova Reading   TerraNova Reading   19
10005   2003-11-17 00:00:00 TerraNova Science   TerraNova Science   26
10005   2003-11-17 00:00:00 TerraNova Total Battery TerraNova Total Battery     22
10005   2003-11-17 00:00:00 TerraNova Total Language    TerraNova Total Language    43

【问题讨论】:

有点迷茫什么是主键? 是记录完全重复还是只是PK字段中的值相似 【参考方案1】:

有点跑题了……

您可以使用DECLARE @Good_Records3 TABLE (FieldDefinition...).,而不是使用CREATE TABLE #GOOD_RECORDS3

如果主键位于 measureid 列上,则查询返回的 id 仍然重复。

查询什么

select A.studentid, A.measuredate, a.MEASUREID, A.score_10 
from #GOOD_RECORDS3 a 
join sysobjects so on so.name = 'J5C_Measures_Sys' AND so.type = 'u' 
join syscolumns sc on so.id = sc.id and sc.name = 'score_10' 
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name 
WHERE A.SCORE_10 IS NOT NULL AND A.STUDENTID IS NOT NULL AND A.MEASUREID IS NOT NULL 

返回?没有重复的MEASUREID-values

【讨论】:

对不起,你能看看我更新的查询吗?现在我的 #GOOD_RECORDS3 表有 measurename 和 labelname 列代替 measureID 我刚刚将您查询的输出添加到我的描述中。 嗯。在向其中插入记录之前,您确定表 J5C_MasterMeasures 是空的吗? J5C_Measures_Sys 是什么?表还是视图? J5C_MasterMeasures 在我输入记录之前不为空。 J5C_Measures_Sys 是一个表。【参考方案2】:

我认为问题是在将提取到 #GOOD_RECORDS3 表中的记录插入 J5C_MasterMeasures 表时出现的。请确定 J5C_MasterMeasures PRIMARY KEY 是什么。然后打印 #GOOD_RECORDS3 记录以查找可能违反 J5C_MasterMeasures 主键约束的重复记录。

希望对你有帮助,

【讨论】:

有点,但你能推荐一下这个语法吗? PK = StudentID, MeasureDate, (MeasureName + ' ' + LabelName)【参考方案3】:

首先声明一个用于存储重复细节的表

declare @dupetable table(did int, dcount int)

然后声明两个变量,一个用于存储重复记录的总数,一个作为循环计数器:

declare @dupecount int, @loopcounter int

然后用重复的记录列表和每个记录的重复数填充重复表:

insert into @dupetable  --Populate duplicate table
(did, dcount)
select id, COUNT(*)
from #GOOD_RECORDS3  
group by id                 --Replace ID with whatever the primary key is
having COUNT(*) > 1

接下来,获取重复记录的总数:

select @dupecount = COUNT(*)    
from @dupetable  

然后初始化循环计数器:

set @loopcounter = 0

然后代码应该遍历重复表,选择最上面的记录,删除它的所有重复条目,然后从临时@dupetable 中删除它:

while  @loopcounter < @dupecount   --Loop through duplicate records
begin
select * from @dupetable 
set @loopcounter = @loopcounter  + 1    --Increase the counter by 1
Declare @ldid int, @ldcount int         --Declare variables for storing the duplicate id and the number of dupes
select top 1 @ldid = did, @ldcount = dcount  --Populate those variables
from @dupetable 
delete from @dupetable      --Remove record from dupe table
where did = @ldid 
declare @rcval int      --Declare variable for setting rowcount
set @rcval = @ldcount - 1   --Set the rowcount val to the number of duplicate rows -1
set rowcount  @rcval        --Set the rowcount val to the number of duplicate rows -1
delete from @testtbl        --Delete the duplicate records from the table
where id = @ldid
end     --End loop

它不是太优雅,但我相信它有效。

【讨论】:

很棒的 cmets,但是,我在 @dupetable 中的所有字段都是 varchars,所以我无法从字符串错误转换。我的 ID 是 3 列的复合 PK。而且这个 ID 并不总是看起来像一个数字。大部分条目是字符串,如 '2009456',但也有少数是字符串,如 'L' 您需要将 @ldid 声明为 varchar 而不是 int。 PK 的数据类型无关紧要,此脚本查找具有匹配 PK 值的记录并删除除 1 之外的所有记录。您只需相应更改 @dupetable 和 @ldid 的数据类型

以上是关于如何制定 T-SQL 以避免主键约束?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式禁用主键约束?

如何在数据库表中添加多个主键约束

主键约束,外键约束,空值约束,默认值约束,唯一约束,检查约束的各个作用是啥?

Oracle如何添加主键约束

SQL server 数据库 用T-SQL语句创建以下四张表 求代码指导

Oracle数据库主键约束与唯一索引有啥区别?