2017-08-04 1 views
0

Ich versuche, doppelte INSERTs in einer Tabelle zu erkennen und stillschweigend zu verwerfen, und wenn ein Duplikat erkannt wurde, gebe die ID (Primärschlüssel) des vorhandenen Datensatzes zurück. Andernfalls fügen Sie den Datensatz ein und geben Sie die neue ID zurück.Rails Postgres Einfügen von doppelten Zeilenprüfungsproblemen

Ich kann dies entweder mit einer Regel oder einem Trigger, aber beide haben Nachteile. Hier ist ein Beispiel für meine Regel:

Testen Sie dies in einer SQL-Konsole oder psql mit einem INSERT funktioniert gut. Wenn es einen Duplikat gibt, wird die ID des ersten existierenden Datensatzes zurückgegeben und nicht der INSERT. Ansonsten wird es mit dem INSERT weitergehen. In Rails schlägt es jedoch fehl und gibt diesen Fehler zurück:

FEHLER: INSERT RETURNING für Relation "territory_products" kann nicht ausgeführt werden TIPP: Sie benötigen eine bedingte ON INSERT DO INSTEAD-Regel mit einer RETURNING-Klausel.

zu einem TRIGGER bewegen, versuche ich dies:

CREATE OR REPLACE Function territory_products_ignore_dups() Returns Trigger 
As $$ 
Begin 
If Exists (
    Select id From territory_products tp 
    Where tp.territory_id = NEW.territory_id And tp.product_id = NEW.product_id    
) Then 
    Return NULL; 
End If; 
Return NEW; 
End; 
$$ Language plpgsql; 

Create Trigger territory_products_ignore_dups 
Before Insert On territory_products 
For Each Row 
Execute Procedure territory_products_ignore_dups(); 

Dies auch gut funktioniert, außer, dass ich nicht bekommen kann die bestehende ID, wegen der Rückkehr NULL zurück (was erforderlich ist, um nicht zuzulassen der INSERT).

Kann jemand eines dieser Probleme lösen, so bekomme ich das Ergebnis, das ich suche? (Verwerfen Sie z. B. die INSERT-Datei im Falle eines Duplikats und geben Sie die ID des vorhandenen Datensatzes zurück. Wenn die INSERT-Operation erfolgreich ist, geben Sie die ID des neuen Datensatzes zurück).

+4

Warum nicht einfach eine Einzigartigkeit Validierung in Rails erstellen und eine Verbindung Index in PG hinzufügen gegen Rennbedingungen zu schützen? – max

+0

Mach was max gesagt. Erzwingt nur eindeutige Datensätze und Sie können nur eine Aktualisierung durchführen, wenn der Datensatz existiert. – bkunzi01

+0

Eine Eindeutigkeitsüberprüfung ist in Situationen mit hohem Datenaufkommen nicht vollsicher, da Rails im Grunde nur einen SELECT ausführt, um die Überprüfung vor dem INSERT durchzuführen. Außerdem werden wir manchmal Updateskripte auf der Datenbank ausführen, also möchten wir, dass die Überprüfung dort ist, aber ohne Ausnahmen überall zu werfen. – BeachBum

Antwort

0

einen eindeutigen Index zu Ihrer Datenbank hinzufügen:

# migration file 
add_index : territory_products, [:territory_id, :product_id], unique: true 

In Ihrer Logik Look für den vorhandenen Datensatz oder erstellen, wenn nicht vorhanden. Es wird eine Ausnahme im Falle einer Race Condition ausgelöst. Suchen Sie einfach erneut nach dem Datensatz.

#logic when finding/creating record 
begin 
    TerritoryProduct.where(territory_id: params[:territory_id], product_id: params[:product_id]).first_or_create! 
rescue ActiveRecord::RecordNotUnique 
    # In case it already exists 
    TerritoryProduct.where(territory_id: params[:territory_id], product_id: params[:product_id]).first 
end 
+0

Ok, ich werde das kaufen. Aber ich habe versucht, Ausnahmen zu vermeiden, sowohl in Rails, als auch während der Eingabe von Skripten in die Datenbank. Ignorieren Sie einfach Duplikate und geben Sie eine vorhandene ID zurück, falls vorhanden. Gibt es keine Möglichkeit, entweder eine Regel oder einen Trigger dazu zu bringen? – BeachBum

Verwandte Themen