2017-04-22 1 views
0

Ich möchte einen Trigger für eine game_catalog Tabelle erstellen, sodass jedes Mal, wenn ein Benutzer ein Spiel aus seiner Sammlung hinzufügt oder löscht, die Gesamtzahl der Spiele aktualisiert wird. Da die Spielesammlung als ein Text-Array gespeichert ist, entschied ich mich, array_length-Funktion zu verwenden, um die Anzahl der Spiele zu zählen.PostgreSQL-Trigger zum Aktualisieren der Spielanzahl beim Einfügen/Löschen von Array-Elementen

game_catalog

id - BIGSERIAL primary key 
user_id - INTEGER 
game_list - text [] 
game_count - INTEGER 

Ich habe versucht, einen Auslöser zu schaffen, so dass sie die Länge der game_list Spalte nach Einsatz neu berechnet oder zu löschen, aber es funktioniert nicht. Hier ist, was ich habe jetzt:

CREATE OR REPLACE FUNCTION count_games() 
RETURNS TRIGGER AS $$ 
BEGIN 
UPDATE game_catalog 
SET game_count = (SELECT array_length(game_list, 1) from game_catalog) 
WHERE user_id = NEW.user_id; 
RETURN NEW; 
END; 
$$ LANGUAGE plpgsql; 

CREATE TRIGGER count_games 
AFTER INSERT OR DELETE ON game_catalog FOR EACH ROW 
EXECUTE PROCEDURE count_games(); 
+0

seltsam. Wenn die Spieleliste im Array ist, wird kein Einfügen oder Löschen durchgeführt - nur update - um die Zeile für den Benutzer zu aktualisieren, indem das Feld 'game_list' geändert wird ... –

Antwort

1

Also, ein paar Dinge:

  • Ich weiß nicht, Ihren genauen Anwendungsfall, aber dies scheint wie eine schlechte Idee für ein paar Gründe
  • Bitte stellen Sie sicher, dass Sie eine eindeutige Einschränkung für Ihre user_id haben oder dies wird unordentlich (Sie geben user_id für Ihr Update ein. Besser, den Primärschlüssel zu verwenden, wenn Sie irgendwas eingeben, aber das ist nicht wirklich notwendig, wie gezeigt) [EDIT - vergiss es. Ihre Anfrage hat das erledigt. Aber Sie aktualisieren jeden Datensatz für diesen Benutzer ... der bei einer Duplizierung teuer werden könnte ...]
  • Wenn Sie wirklich möchten, dass dieses Element für den Benutzer verfügbar ist, ohne es zu berechnen (und da es immer dasselbe referenziert) Zeile), sieht es so aus, als ob es wirklich in einer Ansicht oder materialisierten Ansicht gehört
  • Üblicherweise sind Trigger-Aggregationen für Aggregationen auf Tabellenebene, wenn viele Daten erwartet werden (dh nicht von Datensatz), und würden in einer separaten Tabelle leben . Wenn es in der gleichen Tabelle ist, laufen Sie das Risiko einer Endlosschleife (Aktualisieren einer Zeile, Auslösen eines Updates, Auslösen eines Updates, etc.)
  • Im Allgemeinen sollten Sie sich viele Fragen stellen, bevor Sie ein Array verwenden oder JSON-Spalte in der relationalen Datenmodellierung. Während Sie möglich sind, können Sie Schmerzen für Ihr zukünftiges Selbst erzeugen
  • Für einen DELETE-Trigger ist NEW undefined (siehe Postgres-Dokumentation zu Triggerfunktionen, sie sind sehr hilfreich und haben einige schöne Beispiele)
  • Wenn Sie den Datensatz selbst bearbeiten Beim Einlesen (effizienter, da keine Select-Abfrage aktiv ist) müssen Sie einen BEFORE-Trigger verwenden, da AFTER-Trigger den Wert der in die Tabelle eingehenden Daten nicht ändern können.

Das heißt, Sie Ihre Trigger anders definieren können, damit es funktioniert:

-- only watch for insert/updates on the game_list column to avoid infinite loop 
-- delete doesn't matter here 
CREATE TRIGGER count_games 
BEFORE INSERT OR UPDATE OF game_list 
ON game_catalog 
FOR EACH ROW 
EXECUTE PROCEDURE count_games(); 

Obwohl eine Ansicht wäre besser:

CREATE OR REPLACE VIEW game_catalog_count AS 
SELECT id, user_id, game_list, array_length(game_list,1) as game_count 
FROM game_catalog; 

Und Ihre Trigger-Funktion ein wenig Verbesserung verwenden konnte (es sei denn, Sie planen, auf andere Zeilen zu verweisen ... aber dann haben Sie andere Probleme in Ihrem Triggerfunktionsdesign):

CREATE OR REPLACE FUNCTION count_games() 
RETURNS TRIGGER AS $$ 
BEGIN 

NEW.game_count := array_length(NEW.game_list, 1); 

RETURN NEW; 
END; 
$$ LANGUAGE plpgsql; 

Hoffe, das ist hilfreich!

Verwandte Themen