cc *_*ung 14 sql postgresql common-table-expression sql-update
我理解如何使用该WITH子句进行递归查询(!!),但我在理解它的一般用途/能力方面遇到了问题.
例如,以下查询更新一条记录,其id通过使用子查询确定,该子查询按时间戳返回第一条记录的id:
update global.prospect psp
set status=status||'*'
where psp.psp_id=(
select p2.psp_id
from global.prospect p2
where p2.status='new' or p2.status='reset'
order by p2.request_ts
limit 1 )
returning psp.*;
Run Code Online (Sandbox Code Playgroud)
这是否适合使用WITH包装器而不是相对丑陋的子查询?如果是这样,为什么?
Erw*_*ter 20
如果可以对涉及的表进行并发写访问,则上述查询中存在竞争条件.考虑:
您的示例可以使用CTE(公用表表达式),但它不会给您任何子查询无法执行的操作:
WITH x AS (
SELECT psp_id
FROM global.prospect
WHERE status IN ('new', 'reset')
ORDER BY request_ts
LIMIT 1
)
UPDATE global.prospect psp
SET status = status || '*'
FROM x
WHERE psp.psp_id = x.psp_id
RETURNING psp.*;
Run Code Online (Sandbox Code Playgroud)
顺便说一下,返回的行将是更新版本.
如果要将返回的行插入另一个表,那么WITH子句就变为必不可少:
WITH x AS (
SELECT psp_id
FROM global.prospect
WHERE status IN ('new', 'reset')
ORDER BY request_ts
LIMIT 1
), y AS (
UPDATE global.prospect psp
SET status = status || '*'
FROM x
WHERE psp.psp_id = x.psp_id
RETURNING psp.*
)
INSERT INTO z
SELECT *
FROM y
Run Code Online (Sandbox Code Playgroud)
使用PostgreSQL 9.1或更高版本可以使用CTE进行数据修改查询.
阅读优秀手册中的更多内容.
Joe*_*ams 10
WITH允许您定义"临时表"以在SELECT查询中使用.例如,我最近编写了一个这样的查询来计算两组之间的变化:
-- Let o be the set of old things, and n be the set of new things.
WITH o AS (SELECT * FROM things(OLD)),
n AS (SELECT * FROM things(NEW))
-- Select both the set of things whose value changed,
-- and the set of things in the old set but not in the new set.
SELECT o.key, n.value
FROM o
LEFT JOIN n ON o.key = n.key
WHERE o.value IS DISTINCT FROM n.value
UNION ALL
-- Select the set of things in the new set but not in the old set.
SELECT n.key, n.value
FROM o
RIGHT JOIN n ON o.key = n.key
WHERE o.key IS NULL;
Run Code Online (Sandbox Code Playgroud)
通过定义"表格" o并n在顶部,我能够避免重复表达式things(OLD)和things(NEW).
当然,我们可能会消除UNION ALL使用a FULL JOIN,但在我的特定情况下我无法做到这一点.
如果我正确理解您的查询,它会这样做:
查找global.prospect中状态为"new"或"reset"的最旧行.
通过在其状态中添加星号来标记它
返回行(包括我们的调整status).
我不认为WITH会简化你的情况.但是,使用FROM子句可能稍微优雅一些:
update global.prospect psp
set status = status || '*'
from ( select psp_id
from global.prospect
where status = 'new' or status = 'reset'
order by request_ts
limit 1
) p2
where psp.psp_id = p2.psp_id
returning psp.*;
Run Code Online (Sandbox Code Playgroud)
未经测试.如果有效,请告诉我.
它几乎就是你已经拥有的,除了:
这可以很容易地扩展到更新多行.在使用子查询表达式的版本中,如果子查询已更改为生成多行,则查询将失败.
我global.prospect在子查询中没有别名,所以它更容易阅读.由于这使用了一个FROM子句,如果您不小心引用了正在更新的表,您将收到错误.
在您的版本中,每个项目都会遇到子查询表达式.虽然PostgreSQL应该对此进行优化并且仅对表达式进行一次计算,但如果您不小心引用了列psp或添加了volatile表达式,则此优化将会消失.
| 归档时间: |
|
| 查看次数: |
23538 次 |
| 最近记录: |