it-swarm.com.de

Verletzung der PRIMARY KEY-Einschränkung. Es kann kein doppelter Schlüssel in ein Objekt eingefügt werden - SQL Server

Ich habe ein Projekt geerbt und ich habe einen SQL-Fehler, den ich nicht sicher bin, wie ich das Problem beheben kann. 

Auf einer E-Commerce-Site fügt der Code Informationen zum Versand von Bestellungen in eine andere Datenbanktabelle ein. 

Hier ist der Code, der die Informationen in die Tabelle einfügt:

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);

Es funktioniert korrekt, gibt jedoch auch den folgenden SQL-Fehler aus:

Verletzung der PRIMARY KEY-Einschränkung 'PK_AC_Shipping_Addresses'. Einfügen von .__ nicht möglich. Doppelter Schlüssel im Objekt 'dbo.AC_Shipping_Addresses'. Der doppelte Schlüsselwert ist (165863).

Wenn ich ähnliche Fragen lese, sollte ich die ID in der Erklärung angeben. 

Ist das korrekt? Wie kann ich den Code anpassen, um dieses Problem zu beheben?

Jede Hilfe wird sehr geschätzt!

7

Ziemlich sicher, dass pk_OrderID der PK von AC_Shipping_Addresses ist 

Sie versuchen, ein Duplikat über die _Order.OrderNumber einzufügen 

Mach einen 

select * from AC_Shipping_Addresses where pk_OrderID = 165863;

oder wählen Sie Anzahl (*) ....

Ziemlich sicher, dass Sie eine Reihe zurückbekommen. 

Was es Ihnen sagt, ist, dass Sie bereits pk_OrderID = 165863 verwenden und keine andere Zeile mit diesem Wert haben können. 

wenn Sie nicht einfügen möchten, wenn eine Zeile vorhanden ist 

insert into table (pk, value) 
select 11 as pk, 'val' as value 
where not exists (select 1 from table where pk = 11) 
3
paparazzo

Ich habe den gleichen Fehler in einer wiederhergestellten Datenbank erhalten, als ich versuchte, einen neuen Datensatz mit dem EntityFramework einzufügen. Es stellte sich heraus, dass die Indentity/Seed die Dinge vermasselte.

Mit einem Reseed-Befehl wurde der Fehler behoben.

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

Welchen Wert übergeben Sie an den Primärschlüssel (vermutlich "pk_OrderID")? Sie können den Wert für das automatische Inkrementieren einrichten. Dann sollte es nie ein Problem geben, wenn der Wert dupliziert wird. Der DB kümmert sich darum. Wenn Sie einen Wert selbst angeben müssen, müssen Sie Code schreiben, um den maximalen Wert für dieses Feld zu bestimmen, und diesen Wert dann erhöhen. 

Wenn Sie eine Spalte mit dem Namen "ID" oder eine solche haben, die in der Abfrage nicht angezeigt wird, ist dies in Ordnung, solange sie auf Autoincrement eingestellt ist. Dies ist jedoch wahrscheinlich nicht der Fall, oder Sie sollten keine Fehlermeldung erhalten. Sie sollten auch besser eine einfachere Abfrage schreiben und Params verwenden. Wie der junge Mensch von nunmehr neun Jahren herleitet, lassen Sie Ihre Datenbank für SQL-Injection-Angriffe offen, wenn Sie einfach die vom Benutzer eingegebenen Werte eingeben. Zum Beispiel könnten Sie eine Methode wie diese haben:

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;
}

... das heißt so:

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

Sie müssen es nicht, aber ich speichere die Abfrage separat:

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

Sie können sicherstellen, dass Sie einen bereits vorhandenen Wert nicht einfügen, indem Sie (Pseudocode) verwenden:

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

Die Abfrage ist so etwas wie "SELECT COUNT FROM TABLE WHERE BLA = @CANDIDATEIDVAL" und der Wert ist die ID, die Sie möglicherweise einfügen möchten:

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

Justin möchte wissen, ob das funktioniert:

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

Was scheint mir zu funktionieren, ist:

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

Um zu verhindern, dass ein bereits vorhandener Datensatz eingefügt wird. Ich würde prüfen, ob der ID-Wert in der Datenbank vorhanden ist. Für das Beispiel einer Tabelle, die mit einem IDENTITY PRIMARY KEY erstellt wurde:

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

Wenn JANE DOE und JOE BROWN bereits in der Datenbank vorhanden sind. 

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

DATENBANK AUSGABE von TABELLE [dbo]. [Personen] werden sein:

ID    LastName   FirstName
1     DOE        Jane
2     BROWN      JOE

Ich würde prüfen, ob ich einen vorhandenen Datensatz aktualisieren oder einen neuen einfügen sollte. Als folgendes Java-Beispiel: 

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

Dies kann mehrere Ursachen haben, und dies hängt auch davon ab, was Sie in Ihrer Datenbank eingerichtet haben.

Erstens könnten Sie einen PK in der Tabelle verwenden, der auch eine FK zu einer anderen Tabelle ist, die die Beziehung 1-1 herstellt. In diesem Fall müssen Sie möglicherweise ein Update anstelle eines Inserts durchführen. Wenn Sie wirklich nur einen Adressdatensatz für eine Bestellung haben können, kann dies der Fall sein.

Als Nächstes könnten Sie einen manuellen Prozess verwenden, um die ID im Voraus zu bestimmen. Das Problem bei diesen manuellen Prozessen ist, dass sie Race-Bedingungen erstellen können, bei denen zwei Datensätze dieselbe letzte ID haben und diese um eins erhöhen, dann kann der zweite Datensatz eingefügt werden. 

Drittens können Sie bei der Abfrage an die Datenbank zwei Datensätze erstellen. Um festzustellen, ob dies der Fall ist, führen Sie Profiler aus, um genau zu sehen, welchen SQL-Code Sie senden, und wenn ti eine select-Klausel anstelle einer values-Klausel ist. Führen Sie dann select aus und prüfen Sie, ob aufgrund der Verknüpfungen einige Datensätze doppelt vorhanden sind . Selbst wenn Sie Code im laufenden Betrieb erstellen, ist der erste Schritt zur Fehlerbehebung IMMER, den Profiler auszuführen und zu sehen, ob das gesendet wurde, was Sie erwartet hatten.

0
HLGEM

Nicht die Antwort von OP, aber da dies die erste Frage war, die für mich in Google auftauchte, möchte ich hinzufügen, dass Benutzer, die danach suchen, möglicherweise ihre Tabelle neu besetzen müssen, was für mich der Fall war

DBCC CHECKIDENT(tablename)
0
Renet