我正在尝试基于简单条件删除行,如果满足条件,请删除行,否则更新行。基本上,我使用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))))
我要寻找的只是打一次数据库。
答案 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。调用一个函数为您进行删除。那可以:
SELECT ... FOR UPDATE
)B。编写一个"BEFORE DELETE“触发器。
这可以检查标志的状态,如果未设置,则将其设置而不是删除(返回NULL)。如果该标志已经设置,请继续删除操作。
按我的喜好,有时候触发可能有些“神奇”。如果您不知道他们在那里,那么可能会造成混乱。不过,在这种情况下,我认为触发器可能是一个不错的选择。
答案 2 :(得分:-1)
请参见https://wiki.postgresql.org/wiki/MergeTestExamples中的“与质量合并行动”