Jam*_*ies 6 sql postgresql sql-update
使用Postgres,我可以执行更新语句并返回受推荐影响的行.
UPDATE accounts
SET status = merge_accounts.status,
field1 = merge_accounts.field1,
field2 = merge_accounts.field2,
etc.
FROM merge_accounts WHERE merge_accounts.uid =accounts.uid
RETURNING accounts.*
Run Code Online (Sandbox Code Playgroud)
这将为我提供与该WHERE子句匹配的所有记录的列表,但是不会告诉我操作实际更新了哪些行.
在这个简化的用例中,当然简单地添加另一个防护是微不足道的AND status != 'Closed,但是我的真实世界用例涉及从10,000个行的合并表中更新潜在的几十个字段,我希望能够检测哪些行实际上已经改变了,它们与之前的版本相同.(期望很少的行实际上会改变).
到目前为止我得到的最好的是
UPDATE accounts
SET x=..., y=...
FROM accounts as old WHERE old.uid = accounts.uid
FROM merge_accounts WHERE merge_accounts.uid = accounts.uid
RETURNING accounts, old
Run Code Online (Sandbox Code Playgroud)
这将返回一个新旧行的元组,然后可以在我的Java代码库本身内部进行区分 - 但这需要大量额外的网络流量并且可能容易出错.
理想的情况是能够让postgres返回实际有任何值更改的行 - 这可能吗?
在github上这是一个更真实的例子,我正在做的事情,结合到目前为止的一些建议.
使用Postgres 9.1,但如果需要可以使用9.4.要求是有效的
由于这个问题已经打开,我现在已经完成了大部分工作,虽然我不确定我的方法是否是一个好主意 - 它有点被黑客攻击.
这节省了昂贵的更新和昂贵的支票UPDATE.
要使用提供的新值更新每个列(如果有任何更改):
UPDATE accounts a
SET (status, field1, field2) -- short syntax for ..
= (m.status, m.field1, m.field2) -- .. updating multiple columns
FROM merge_accounts m
WHERE m.uid = a.uid
AND (a.status IS DISTINCT FROM m.status OR
a.field1 IS DISTINCT FROM m.field1 OR
a.field2 IS DISTINCT FROM m.field2)
RETURNING a.*;Run Code Online (Sandbox Code Playgroud)
由于PostgreSQL的MVCC模型,对行的任何更改都会写入新的行版本.更新单个列几乎与一次更新行中的每个列一样昂贵.只要你需要更新任何东西,重写其余部分几乎不需要任何费用.
细节:
如果行类型的accounts和merge_accounts是相同的,并要采取一切从merge_accounts入accounts,有比较全行类型的快捷方式:
UPDATE accounts a
SET (status, field1, field2)
= (m.status, m.field1, m.field2)
FROM merge_accounts m
WHERE a.uid = m.uid
AND m IS DISTINCT FROM a
RETURNING a.*;Run Code Online (Sandbox Code Playgroud)
这甚至适用于NULL值.手册中的详细信息.
但它不适用于您的本土解决方案(引用):
merge_accounts除了所有非pk列都是数组类型之外,它们是相同的
它要求行类型兼容,即每个列共享相同的数据类型,或者至少在两种类型之间注册了隐式转换.
UPDATE accounts a
SET (status, field1, field2)
= (COALESCE(m.status[1], a.status) -- default to original ..
, COALESCE(m.field1[1], a.field1) -- .. if m.column[1] IS NULL
, COALESCE(m.field2[1], a.field2))
FROM merge_accounts m
WHERE m.uid = a.uid
AND (m.status[1] IS NOT NULL AND a.status IS DISTINCT FROM m.status[1]
OR m.field1[1] IS NOT NULL AND a.field1 IS DISTINCT FROM m.field1[1]
OR m.field2[1] IS NOT NULL AND a.field2 IS DISTINCT FROM m.field2[1])
RETURNING a.*Run Code Online (Sandbox Code Playgroud)
m.status IS NOT NULL如果不应更新的列为NULL,则可以正常工作merge_accounts.
m.status <> '{}'如果你操作空数组.
m.status[1] IS NOT NULL涵盖两种选择.
就像Jayadevan发布的那样,我之前已经回答过:
| 归档时间: |
|
| 查看次数: |
3072 次 |
| 最近记录: |