违反主键约束PK。无法在对象(表1)中插入重复键,重复键值为(Col1,Col2,Col3,Col4)

时间:2019-01-05 10:02:33

标签: sql sql-server asp-classic oledb

我有一个产品条目页面,我们不断在数据库中添加产品条目。

产品位置明智地有2个系列。例如ABCTMP(Series(1-max))和XYZ(Series(1-max))。

表具有主键约束,该约束是4列的组合。在4中,只有一个在递增序列组合明智时会出现问题。

第一列是如上所述的位置信息产品代码,它的数据类型为char(20),因为它存储着ABCTMP01之类的值并通过经典的asp代码。我们将最后一个01值增加一个到现有值中。

现在,当最后一个值达到99并变为100时面临问题。它会通过代码生成代码100,但无法插入数据库,并给出此错误是由于数据库中已有条目所致。

重复的关键部分与我在主题/标题中提到的相同。如果我从记录号表中删除记录。 100进行检查,它通过上述查询和上述经典的asp代码为我提供了正确的99记录,它生成的下一个代码为99 + 1 =100。

但是当我再次尝试为101添加下一个系列记录时,即使通过SQL mgt studio,它也给了我下面的错误。

违反主键约束“ PK”。无法在对象“ prdct_mst_tab”中插入重复的密钥。重复的键值为(PWATERTMP100,006,Y,01)。该声明已终止。

已尝试通过删除约束并将数据类型char(20)的大小更改为char(30),因为对表存在依赖性。但是没有用。然后,尝试通过将数据类型从char(30)更改为varchar(30),仍然无法正常工作。然后再次尝试手动

  

执行插入命令

在SQL本身中,但是第101条记录发生了相同的错误。

在生成下一个系列之前,有一条select语句来检查最新插入的记录,该记录将在以后递增。

要生成下一个记录101,则select语句必须显示最后插入的记录100,但仍给出第99条记录,并且代码再次生成为100,并且错误继续。我不明白为什么在SQL mgt studio中执行SELECt语句时它没有取得第100条记录。该PWATERTMP100列的数据类型为char(20)。

下面是我用于序列生成的经典asp代码和用于位置明智产品的记录计数的SQL'SELECT top 1 *'语句。

select top 1 * 
from prdct_mst_tab 
where pmt_prdct_cd like 'PWATER%' 
and pmt_umt_unit_cd='006' 
AND PMT_CMT_CMPNY_CD='01' 
order by pmt_prdct_cd desc

经典ASP代码:-

If recordset.eof Then 
    getcode="ABCTMP01" 
Else
    getcode = clng(Mid(recordset("Column1"),10,20))
        response.write("Hello" & getcode)
    getcode = getcode +1
        response.write("<br />Hello" & getcode)
    getcode = "ABCTMP" & getcode
        response.write("<br />Hello" & getcode)
End if

以下用于在数据库表中添加生成的产品代码。

Sql如下

select * from Table1
recordset.open sql,con,3,2
recordset.addnew
recordset("Column1")=getcode
recordset.update 
recordset.close
  

注意:上面给出的值是示例一。

我希望即使记录从99变为100也要插入记录,这意味着代码将变为ABCTMP99-ABCTMP100,并从series开始100范围(3位数字),例如100、101、102 ....

1 个答案:

答案 0 :(得分:1)

问题在于在此排序:

select top 1 * from prdct_mst_tab 
where pmt_prdct_cd like 'PWATER%' 
and pmt_umt_unit_cd='006' 
AND PMT_CMT_CMPNY_CD='01' 
order by pmt_prdct_cd desc

没有按照您的期望做。

尝试在Management Studio中运行它:

select * from prdct_mst_tab 
where pmt_prdct_cd like 'PWATER%' 
and pmt_umt_unit_cd='006' 
AND PMT_CMT_CMPNY_CD='01' 
order by pmt_prdct_cd desc

您会看到100出现在之前 99,因为它是按字母数字顺序而不是数字顺序排列的。

实际上,您还会看到10出现在9之前-您是如何克服这个问题的?

您有一个基本的设计缺陷。我将通过提出一个解决方案来添加,该解决方案可以巩固设计缺陷并引入新的错误。但这会给你结果。

一种解决方法是要执行以下操作:

select 
MAX(
  CASE 
    WHEN ISNUMERIC(RIGHT(RTRIM(pmt_prdct_cd),3)) = 1 
    THEN RIGHT(RTRIM(pmt_prdct_cd),3)
    ELSE '0' + RIGHT(RTRIM(pmt_prdct_cd),2)
  END
) As LargestNumber
from prdct_mst_tab 
where pmt_prdct_cd like 'PWATER%' 
and pmt_umt_unit_cd='006' 
AND PMT_CMT_CMPNY_CD='01' 

这是做什么的?

它检查后三个字符是否为数字。如果它使用它。

如果不是数字,它将抓住最后两个字符,并在前面放置零。

然后从所有这些中选择最大的数字。

注意-这将返回一个数字,但不会返回完整的产品代码。因此,您需要删除试图将数字拉出的ASP Mid代码。

这可能会起作用,直到您找到尚未提及的其他数据或案例。例如,如果有不是数字的结尾字符。或者当您需要四个字符的数字时

没错-您有一个基本的设计缺陷,这只会延长问题,增加复杂性并会带来更多错误

一些基本观察结果:

  • char对此是错误的数据类型

  • 它存在并发问题-如果两个请求同时调用此请求(很容易从Web应用程序完成),它将返回相同的数字,并且它们都尝试插入重复的值

  • 您不应分配和存储这样的递增数字。只需在数据库中使用IDENTITY

我想因为您使用的是经典ASP,所以您无法重新设计它。

您需要确定是否要使用会引入新错误或适当修复的方法对其进行修补。

每个产品代码确实都需要像这样在自己的域内递增吗? ABC01然后DEF02然后XYZ03有什么问题吗?