2
votes

PostgreSQL supprime la ligne si la condition est remplie, sinon met à jour une valeur

J'essaye de supprimer une ligne basée sur une condition simple, si les conditions sont remplies, supprimez la ligne sinon mettez à jour la ligne. Fondamentalement, je marque mes données avec is_deleted , alors effectuez une suppression si is_deleted est égal à true, sinon, définissez la valeur is_deleted sur true.

Pour le moment, ce que je fais est une simple requête, vérifiez le is_deleted à partir des données interrogées et faites quelque chose en fonction de cela.

Un pseudo-code très simple écrit en clojure ($ n est juste un espace réservé pour les arguments de position):

(defn find-by-username 
  [db username]
  "SELECT * FROM users WHERE username = $1") ;; to illustrate the query

(defn delete-by-username-impl
  [db username]
  "DELETE FROM users WHERE username = $1")

(defn set-is-deleted
  [db username]
  "UPDATE users SET is_deleted = true WHERE username = $1")

(defn delete-by-username 
  [db username]
  (let [user (find-by-username db username)]
    (if (:is-deleted user)
      (delete-by-username-impl db username)
      (set-is-deleted db username))))

Ce que je recherche, c'est n'a frappé la base de données qu'une seule fois.


1 commentaires

Vous pouvez toujours encapsuler la logique dans une procédure où: est-supprimé serait une entrée dans la procédure, cela réduirait également le nombre de fonctions dont vous auriez besoin pour interagir avec la base de données en premier lieu.


3 Réponses :


-1
votes

Voir «Action de fusion avec Quals» dans https://wiki.postgresql.org/wiki/MergeTestExamples


4 commentaires

Lisez toujours les pages vers lesquelles vous créez un lien "Cela n'a jamais été intégré à PostgreSQL et nécessite un travail important pour être de qualité de production"


Salut, merci pour votre réponse, malheureusement cette fonctionnalité n'est jamais implémentée.


@RichardHuxton Des opinions à ce sujet? Est-ce même faisable?


Censé être dans 11. Mais je ne peux pas le trouver maintenant. Probablement inversé. La solution rapide consiste à écrire votre propre procédure stockée.



0
votes

Il y a deux options évidentes

A. Appelez une fonction pour effectuer la suppression à votre place. Cela peut:

  1. verrouiller la ligne ( SELECT ... FOR UPDATE )
  2. lire le paramètre d'indicateur actuel
  3. supprimer la ligne si l'indicateur est défini
  4. définir l'indicateur si ce n'est pas le cas

B. Écrivez un déclencheur "BEFORE DELETE ".

Cela peut vérifier l'état de l'indicateur et s'il n'est pas défini, le définir au lieu de le supprimer (retourner NULL). Si l'indicateur est déjà défini, laissez l'opération de suppression se poursuivre.

Les déclencheurs peuvent parfois être un peu «magiques» à mon goût. Si vous ne savez pas qu'ils sont là, cela peut être déroutant. Dans ce cas cependant, je pense qu'un déclencheur est probablement un bon choix.


0 commentaires

1
votes

Qu'entendez-vous par accéder à la base de données une seule fois? Vous exécutez une requête? Ensuite, vous pouvez combiner toutes les requêtes en une seule:

;; Insert two new fruits atomically
(jdbc/with-db-transaction [trans-conn db-spec]
  (jdbc/insert! trans-conn :fruit {:name "Fig" :cost 12})
  (jdbc/insert! trans-conn :fruit {:name "Date" :cost 14}))
;; -> ({:grade nil, :unit nil, :cost 14, :appearance nil, :name "Date"})

Si vous voulez exécuter toutes les requêtes ensemble ou aucune d'entre elles dans un contexte isolé (afin que les autres clients ne puissent pas changer l'état comme le is_deleted pendant l'exécution des requêtes), vous pouvez encapsuler les requêtes séparées dans une transaction à l'aide d'un transaction de base de données :

Les transactions de base de données sont disponibles pour garantir que plusieurs opérations sont effectuées de manière atomique (c'est-à-dire toutes ou aucune). La macro clojure.java.jdbc / with-db-transaction crée une connexion prenant en charge les transactions à partir de la spécification de la base de données. Utilisez la connexion compatible avec les transactions pendant toute la durée de la transaction:

IF (SELECT is_deleted FROM users WHERE username = $1) THEN
  DELETE FROM users WHERE username = $1
ELSE
  UPDATE users SET is_deleted = true WHERE username = $1
END IF;


0 commentaires