web-dev-qa-db-ja.com

PRIMARY KEY制約の違反。オブジェクトに重複キーを挿入できません-SQL Server

プロジェクトを継承しましたが、修正方法がわからないSQLエラーが発生しています。

Eコマースサイトでは、コードが注文配送情報を別のデータベーステーブルに挿入しています。

以下は、情報をテーブルに挿入するコードです。

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("'", "''") + "'";
}
else
{
  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("'", "''") + "'";
}
else
{
  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を宣言する必要があるようです。

あれは正しいですか?この問題を修正するには、どのようにコードを調整しますか?

どんな助けも大歓迎です!

8

Pk_OrderIDがAC_Shipping_AddressesのPKであることを確認してください

そして、_Order.OrderNumberを介して複製を挿入しようとしています

やる

select * from AC_Shipping_Addresses where pk_OrderID = 165863;

または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) 
2
paparazzo

EntityFrameworkを使用して新しいレコードを挿入しようとしたときに、復元されたデータベースで同じエラーが発生していました。 Indentity/Seedが物事を台無しにしていたことが判明しました。

再シードコマンドを使用して修正しました。

DBCC CHECKIDENT ('[Prices]', RESEED, 4747030);GO
11
Ger Groot

主キー(おそらく「pk_OrderID」)に渡す値は何ですか?自動インクリメントに設定することができます。そうすれば、値の複製に問題はないはずです-DBがそれを処理します。自分で値を指定する必要がある場合は、そのフィールドの最大値が何であるかを判断するコードを作成し、それをインクリメントする必要があります。

「ID」という名前の列またはクエリに表示されない列がある場合は、自動インクリメントに設定されていれば問題ありませんが、おそらくそうではないか、そのエラーメッセージは表示されません。また、より簡単なクエリを作成し、paramsを使用することをお勧めします。したがって、9年前に推測されたように、ユーザーが入力した値を単純に入力した場合、データベースは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.
2
B. Clay Shannon

既に存在するレコードを挿入しないようにします。 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');

TABLE [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
}
1
QA Specialist

これはいくつかの原因で発生する可能性があり、データベースに設定した内容によって多少異なります。

まず、テーブルでPKを使用し、別のテーブルへのFKでもある場合、1-1の関係を作成できます。この場合、挿入ではなく更新を行う必要がある場合があります。実際に注文に対して1つの住所レコードしか持てない場合、これが起こっている可能性があります。

次に、何らかの手動プロセスを使用して、事前にidを決定することができます。これらの手動プロセスの問題は、2つのレコードが同じ最後のIDを取得して1つ増やし、2つ目のレコードが挿入できないという競合状態を作成できることです。

3番目に、データベースに送信されるときにクエリを実行すると、2つのレコードが作成される場合があります。これが当てはまるかどうかを判断するには、プロファイラーを実行して、送信するSQLコードを正確に確認し、tiがvalue句ではなくselectである場合、selectを実行して、結合によって重複するレコードが発生したかどうかを確認します。このようにオンザフライでコードを作成している場合でも、最初のトラブルシューティング手順は常にプロファイラーを実行し、送信されたものが送信されたものであるかどうかを確認することです。

0
HLGEM

OPの答えではありませんが、これはグーグルで私のためにポップアップされた最初の質問だったので、これを検索しているユーザーがテーブルを再シードする必要があるかもしれないことを追加したいと思います

DBCC CHECKIDENT(tablename)
0
Renet