添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

违反了PRIMARY KEY约束。不能在对象中插入重复的键

19 人关注

我继承了一个项目,我遇到了一个SQL错误,我不知道如何解决。

在一个电子商务网站上,代码正在将订单运输信息插入到另一个数据库表中。

下面是将信息插入到表中的代码。

string sql = "INSERT INTO AC_Shipping_Addresses   
(pk_OrderID, FullName, Company, Address1, Address2, City, Province, PostalCode, CountryCode, Phone, Email, ShipMethod, Charge_Freight, Charge_Subtotal)  
VALUES (" + _Order.OrderNumber;
sql += ", '" + _Order.Shipments[0].ShipToFullName.Replace("'", "''") + "'";
if (_Order.Shipments[0].ShipToCompany == "")
  sql += ", '" + _Order.Shipments[0].ShipToFullName.Replace("'", "''") + "'";
  sql += ", '" + _Order.Shipments[0].ShipToCompany.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Address1.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Address2.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.City.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Province.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.PostalCode.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Country.Name.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Phone.Replace("'", "''") + "'";
if (_Order.Shipments[0].ShipToEmail == "")
  sql += ",'" + _Order.BillToEmail.Replace("'", "''") + "'";
  sql += ",'" + _Order.Shipments[0].ShipToEmail.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].ShipMethod.Name.Replace("'", "''") + "'";
sql += ", " + shippingAmount;
sql += ", " + _Order.ProductSubtotal.ToString() + ")";
bll.dbUpdate(sql);

它工作正常,但它也输出了以下SQL错误。

违反了PRIMARY KEY约束 "PK_AC_Shipping_Addresses"。不能插入 不能在对象'dbo.AC_Shipping_Addresses'中插入重复的键。重复键的值 是(165863)。

通过阅读类似的问题,我似乎应该在语句中声明ID。

这是正确的吗?我将如何调整代码来解决这个问题?

10 个评论
第1步)在运行前找出 sql 的值。第0步)改变为使用绑定值进行查询,而不是串联。谷歌 "SQL注入 "了解原因。
你传递给主键的值是什么(估计是 "pk_OrderID")?你可以把它设置为自动增量,然后就不会有重复值的问题了--DB会处理这个问题。如果你需要自己指定一个值,你需要写代码来确定该字段的最大值是什么,然后再增量。
你的唯一键字段是什么? 看起来你的订单号是重复的,你可能在你的表中已经有了165863号订单,而你正试图插入一个重复的。
如果PK值已经存在,那么你只需更新它,或者你必须在插入新值之前删除之前的值。 string sql = "DELETE FROM AC_Shipping_Addresses where pk_OrderID = " + _Order.OrderNumber;
如果你有一个名为 "ID "或类似的列,但没有显示在查询中,只要它被设置为自动递增就可以了 - 但它可能不是,否则你不应该得到那个错误的味精。另外,你最好写一个更容易看懂的查询并使用参数。正如九年前的小伙子所推断的那样,如果你只是简单地插入用户输入的值,你就会让你的数据库受到SQL注入攻击。
它采取的是订单ID,并将其插入pk_OrderID中,所以这应该永远不会是一个重复的。这是唯一唯一的值。是否有一个简单的方法,在插入前先检查_Order.OrderNumber与可能重复的pk_OrderID值?
@B.ClayShannon 没有一个ID列。可用的列名都在插入语句中。你能不能帮我转换语句以避免SQL注入?
... 我的上帝,它充满了 "'+"'"'""+ "''" !
至少向我们展示PK_AC_Shipping_Addresses的定义。
sql-server
sql-server-2008
primary-key
Justin Hollender
Justin Hollender
发布于 2016-03-17
7 个回答
Ger Groot
Ger Groot
发布于 2020-07-25
0 人赞同

当我试图使用EntityFramework插入一条新的记录时,我在一个恢复的数据库上得到了同样的错误。结果发现,实体/种子把事情搞砸了。

使用reseed命令解决了这个问题。

DBCC CHECKIDENT ('[Prices]', RESEED, 4747030);GO
    
paparazzo
paparazzo
发布于 2020-07-25
已采纳
0 人赞同

我很确定 pk_OrderID 是一个PK,而你是通过 。 AC_Shipping_Addresses

而你正试图通过 _Order.OrderNumber ,插入一个重复的内容?

select * from AC_Shipping_Addresses where pk_OrderID = 165863;

select count(*)....

非常肯定的是,你会得到一个行的返回。

它在告诉你,你已经使用了pk_OrderID = 165863 ,不能再有另一条带有该值的记录。

如果你想在有行的情况下不插入

insert into table (pk, value) 
select 11 as pk, 'val' as value 
where not exists (select 1 from table where pk = 11)
    
Justin Hollender
我现在正试图添加一些代码,先检查该值。这看起来像是正确的吗?: string exists = "SELECT 1 from AC_Shipping_Addresses where pk_OrderID = " _Order.OrderNumber; if (existence > 0) { // 已经存在 } else { // 插入订单数据
是的,在理论上这是可行的。 但我添加了我更喜欢的东西。
这不是一个很好的答案,开发人员确定主列作为身份的自动增量列!这是一个逃逸代码而不是解决方案:)
B. Clay Shannon-B. Crow Raven
B. Clay Shannon-B. Crow Raven
发布于 2020-07-25
0 人赞同

你传递给主键的值是什么(估计是 "pk_OrderID")?你可以把它设置为自动增量,然后就不会有重复值的问题了--DB会处理这个问题。如果你需要自己指定一个值,你需要写代码来确定该字段的最大值是什么,然后再增量。

如果你有一个名为 "ID "或类似的列,在查询中没有显示,只要它被设置为自动递增就可以了--但它可能不是,否则你不应该得到那个错误味精。另外,你最好写一个更容易看懂的查询并使用参数。正如九年前的那位小伙子所推断的那样,如果你只是简单地插入用户输入的值,你就会让你的数据库受到SQL注入攻击。例如,你可以有一个这样的方法。

internal static int GetItemIDForUnitAndItemCode(string qry, string unit, string itemCode)
    int itemId;
    using (SqlConnection sqlConn = new SqlConnection(ReportRunnerConstsAndUtils.CPSConnStr))
        using (SqlCommand cmd = new SqlCommand(qry, sqlConn))
            cmd.CommandType = CommandType.Text;
            cmd.Parameters.Add("@Unit", SqlDbType.VarChar, 25).Value = unit;
            cmd.Parameters.Add("@ItemCode", SqlDbType.VarChar, 25).Value = itemCode;
            sqlConn.Open();
            itemId = Convert.ToInt32(cmd.ExecuteScalar());
    return itemId;

...被这样调用。

int itemId = SQLDBHelper.GetItemIDForUnitAndItemCode(GetItemIDForUnitAndItemCodeQuery, _unit, itemCode);

你不必这样做,但我把查询分开存储。

public static readonly String GetItemIDForUnitAndItemCodeQuery = "SELECT PoisonToe FROM Platypi WHERE Unit = @Unit AND ItemCode = @ItemCode";

你可以通过(伪代码)来验证你不是要插入一个已经存在的值。

bool alreadyExists = IDAlreadyExists(query, value) > 0;

查询是类似于 "SELECT COUNT FROM TABLE WHERE BLA = @CANDIDATEIDVAL",值是你可能要插入的ID。

if (alreadyExists) // keep inc'ing and checking until false, then use that id value

贾斯汀想知道这是否可行。

string exists = "SELECT 1 from AC_Shipping_Addresses where pk_OrderID = " _Order.OrderNumber; if (exists > 0)...

对我来说,似乎可以工作的是。

string existsQuery = string.format("SELECT 1 from AC_Shipping_Addresses where pk_OrderID = {0}", _Order.OrderNumber); 
// Or, better yet:
string existsQuery = "SELECT COUNT(*) from AC_Shipping_Addresses where pk_OrderID = @OrderNumber"; 
// Now run that query after applying a value to the OrderNumber query param (use code similar to that above); then, if the result is > 0, there is such a record.
    
它正在获取订单ID(_Order.OrderNumber)并将其插入pk_OrderID。有没有一个简单的方法,在插入前先检查_Order.OrderNumber与可能重复的pk_OrderID值?
是的,在你要插入的表中检查这个值;如果它存在,就输入这个数字。你可能需要不断检查,直到找到一个不存在的数字。
要检查这个值,这个语句是否正确? bool alreadyExists = IDAlreadyExists(SELECT COUNT(*) from AC_Shipping_Addresses where pk_OrderID = _Order.OrderNumber, _Order.OrderNumber) > 0。
这应该足够了:"SELECT COUNT(*) from AC_Shipping_Addresses where pk_OrderID = _Order.OrderNumber"
对不起,我以前从未用SQL查询写过if/else语句。会不会像这样? if ("SELECT COUNT(*) from AC_Shipping_Addresses where pk_OrderID = _Order.OrderNumber" != 0) { //do insert }如果没有匹配的值,该语句是否会返回0或NULL?
QA Specialist
QA Specialist
发布于 2020-07-25
0 人赞同

为了防止插入一个已经存在的记录。我将检查ID值是否存在于数据库中。对于一个用IDENTITY PRIMARY KEY创建的表的例子。

CREATE TABLE [dbo].[Persons] (    
    ID INT IDENTITY(1,1) PRIMARY KEY,
    LastName VARCHAR(40) NOT NULL,
    FirstName VARCHAR(40)

当JANE DOE和JOE BROWN已经存在于数据库中。

SET IDENTITY_INSERT [dbo].[Persons] OFF;
INSERT INTO [dbo].[Persons] (FirstName,LastName)
VALUES ('JANE','DOE'); 
INSERT INTO Persons (FirstName,LastName) 
VALUES ('JOE','BROWN');

表[dbo].[Persons]的数据库输出结果将是。

ID    LastName   FirstName
1     DOE        Jane
2     BROWN      JOE

我将检查我是否应该更新一个现有的记录或插入一个新的记录。如下面的JAVA例子。

int NewID = 1;
boolean IdAlreadyExist = false;
// Using SQL database connection
// STEP 1: Set property
System.setProperty("java.net.preferIPv4Stack", "true");
// STEP 2: Register JDBC driver
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
// STEP 3: Open a connection
try (Connection conn1 = DriverManager.getConnection(DB_URL, USER,pwd) {
    conn1.setAutoCommit(true);
    String Select = "select * from Persons where  ID = " + ID;
    Statement st1 = conn1.createStatement();
    ResultSet rs1 = st1.executeQuery(Select);
    // iterate through the java resultset
    while (rs1.next()) {
        int ID = rs1.getInt("ID");
        if (NewID==ID) {
            IdAlreadyExist = true;
    conn1.close();
} catch (SQLException e1) {
    System.out.println(e1);
if (IdAlreadyExist==false) {
    //Insert new record code here
} else {
    //Update existing record code here
    
Renet
Renet
发布于 2020-07-25
0 人赞同

这不是OP的答案,但这是我在谷歌上弹出的第一个问题,我还想补充一点,搜索这个问题的用户可能需要重新填表,我就是这种情况。

DBCC CHECKIDENT(tablename)
    
HLGEM
HLGEM
发布于 2020-07-25
0 人赞同

导致这种情况的原因可能有几种,这在一定程度上取决于你在数据库中设置了什么。

首先,你可能在表中使用了一个PK,这个PK也是另一个表的FK,使得关系变成了1-1。在这种情况下,你可能需要做一个更新,而不是插入。如果你真的只能有一个订单的地址记录,这可能就是发生的情况。