如何制定 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 以避免主键约束?的主要内容,如果未能解决你的问题,请参考以下文章
主键约束,外键约束,空值约束,默认值约束,唯一约束,检查约束的各个作用是啥?