Inserimento di dati in una tabella SQL con chiave primaria. Per i duplicati: consenti errore di inserimento o seleziona prima?

StackOverflow https://stackoverflow.com/questions/411575

  •  03-07-2019
  •  | 
  •  

Domanda

Data una tabella come:

CREATE TABLE dbo.MyTestData (testdata varchar(50) NOT NULL) 

ALTER TABLE dbo.MyTestData WITH NOCHECK ADD CONSTRAINT [PK_MyTestData] PRIMARY KEY  CLUSTERED (testdata) 

E dato che desideriamo un elenco univoco di "testdata" quando abbiamo finito di raccogliere elementi da aggiungere da un elenco di dati esterni con duplicati noti ... Quando si esegue una procedura di inserimento memorizzata, la procedura deve essere scritta per verificare esistenza o dovrebbe solo consentire l'errore? Qual è la pratica più comune? Ho sempre eseguito il test per l'esistenza ma stavo discutendo quest'ultima sera ...

CREATE PROCEDURE dbo.dmsInsertTestData @ptestdata VarChar(50)
AS
  SET NOCOUNT ON

  IF NOT EXISTS(SELECT testdata FROM dbo.MyTestData WHERE testdata=@ptestdata)
  BEGIN
    INSERT INTO dbo.MyTestData (testdata ) VALUES (@ptestdata)
  END

RETURN 0

o semplicemente catturare / ignorare gli errori di violazione PK quando si esegue questo?

CREATE PROCEDURE dbo.dmsInsertTestData @ptestdata VarChar(50)
AS
  SET NOCOUNT ON
  INSERT INTO dbo.MyTestData (testdata ) VALUES (@ptestdata)
RETURN 0
È stato utile?

Soluzione

Lo faccio sempre in una frase:

INSERT INTO dbo.MyTestData (testdata ) VALUES (@ptestdata)
WHERE NOT EXISTS(SELECT 1 FROM dbo.MyTestData WHERE testdata=@ptestdata)

Altri suggerimenti

Il tuo controllo per errori (es. " SE NON ESISTE ... ") può o non può funzionare, perché esiste una potenziale condizione di competizione (se un'altra transazione inserisce il record dopo la tua dichiarazione IF NOT EXISTS ma prima della tua dichiarazione INSERT ).

Pertanto, indipendentemente dal fatto che tu controlli prima, dovresti codificare la tua dichiarazione INSERT come se potesse fallire.

Se vuoi selezionare anche (no, invece) dipende da te e dalla tua UI.

Penso che la maggior parte dei programmatori suggerirebbe di evitare l'eccezione. Non sono sicuro dal punto di vista delle prestazioni in T-SQL, ma in .NET ad esempio, credo che un'eccezione generata sia più costosa di un'istruzione if / else aggiuntiva.

La mia preoccupazione per il primo esempio che hai dato è che non sta restituendo un errore all'utente. Può essere risolto per farlo, ma non lo userei se non restituisse un errore.

Se la tua preoccupazione tra le due possibilità è la prestazione su tavoli di grandi dimensioni, ti suggerisco di testarli entrambi e vedere se uno è significativamente più veloce dell'altro. Se la selezione if è particolarmente complicata e l'inserimento dovrà avvenire per la maggior parte del tempo, è possibile che lasciarlo fallire sia più veloce per la maggior parte del tempo. Se d'altra parte, la possibilità di un input errato è alta e l'if è relativamente semplice come mostrato qui, allora l'altro processo potrebbe essere migliore. Ma solo test reali sulla tua struttura e dati reali e con le tue query reali possono dirti qual è il migliore per le prestazioni in quanto potrebbe essere diverso nelle sitiffertions deiffernt.

Credo che dipenda dalla natura della procedura memorizzata. Fondamentalmente, dovresti gestire gli errori se hai qualcosa a che fare con loro (o incapsularli per i clienti della procedura) e lasciarli propagare se non hai nulla a che fare con loro e non puoi renderli più amichevoli per gli altri strati dell'applicazione.

Se la procedura memorizzata è progettata per inserire dati non elaborati, penso che dovrebbe lasciare l'applicazione per gestire i possibili errori. Se la procedura memorizzata è progettata come un livello di astrazione (e esegue una attività specifica anziché eseguire una istruzione specifica) e può gestire l'errore e fare qualcosa con essa o può segnalarlo in modo grazioso (ad esempio, codici di errore ben definiti) all'applicazione, dovrebbe farlo. Altrimenti, dovrebbe essere l'applicazione a verificare che non stia inserendo dati duplicati, non il database (il database lo ha già applicato con le chiavi primarie).

Per essere intuitivo, è spesso buona norma eseguire SELECT e, se il record esiste già, offrire all'utente la possibilità di visualizzarlo e / o modificarlo.

Ad esempio, se un utente sta aggiungendo un nuovo record cliente, potrebbe voler rivedere le informazioni che sono già state visualizzate per quel cliente. Potrebbero avere ulteriori informazioni da aggiungere al record, ad esempio un numero di telefono.

In questo tipo di scenario, rifiutare di aggiungere il record è meno utile che offrire la possibilità di visualizzare il duplicato esistente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top