PostgreSQL如果满足条件则删除行,否则更新一些值

时间:2019-05-23 23:14:15

标签: postgresql clojure

我正在尝试基于简单条件删除行,如果满足条件,请删除行,否则更新行。基本上,我使用is_deleted标记数据,因此如果is_deleted等于true,请执行删除操作;否则,将is_deleted的值设置为true。

现在我正在做的是一个简单的查询,从查询到的数据中检查is_deleted并根据它进行一些操作。

用clojure编写的非常简单的伪代码($ n只是位置参数的占位符):

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

我要寻找的只是打一次数据库。

3 个答案:

答案 0 :(得分:1)

只打一次数据库意味着什么?运行一个查询?然后,您可以将所有查询合并为一个:

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;

如果您要同时运行所有查询,或者在隔离的上下文中不运行所有查询(以使其他客户端在运行查询时无法像is_deleted标志那样更改状态),则可以将单独的查询包装到事务中使用database transaction

  

数据库事务可用于确保自动执行多项操作(即全部或不执行)。 clojure.java.jdbc / with-db-transaction宏根据数据库规范创建一个支持事务的连接。在交易期间使用可感知交易的连接:

(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"})

答案 1 :(得分:0)

有两个明显的选择

A。调用一个函数为您进行删除。那可以:

  1. 锁定行(SELECT ... FOR UPDATE
  2. 阅读当前标志设置
  3. 如果设置了标志,则删除行
  4. 设置标志,如果不是

B。编写一个"BEFORE DELETE“触发器。

这可以检查标志的状态,如果未设置,则将其设置而不是删除(返回NULL)。如果该标志已经设置,请继续删除操作。

按我的喜好,有时候触发可能有些“神奇”。如果您不知道他们在那里,那么可能会造成混乱。不过,在这种情况下,我认为触发器可能是一个不错的选择。

答案 2 :(得分:-1)

请参见https://wiki.postgresql.org/wiki/MergeTestExamples中的“与质量合并行动”

相关问题