当最大ended_at
未通过时,我正在尝试更新active
表中的test_subscription
和period_end
列。
我正在使用以下查询,但我怀疑这是最惯用的方式。任何关于改进的建议都非常欢迎。
创建表格:
CREATE TABLE test_subscription (
id INTEGER PRIMARY key,
started_at timestamp,
ended_at TIMESTAMP,
active boolean
);
CREATE TABLE test_invoice (
id INTEGER PRIMARY key,
subscription_id INTEGER,
period_start timestamp,
period_end timestamp
);
INSERT INTO test_subscription (id, started_at, ended_at, active)
values(1, '2017-01-01 00:00:00', NULL, TRUE);
INSERT INTO test_subscription (id, started_at, ended_at, active)
values(2, '2017-01-01 00:00:00', NULL, TRUE);
INSERT INTO test_invoice (id, subscription_id, period_start, period_end)
values(1, 1, '2017-01-01 00:00:00', '2017-12-01 00:00:00');
INSERT INTO test_invoice (id, subscription_id, period_start, period_end)
values(2, 1, '2017-12-02 00:00:00', '2019-12-01 00:00:00');
INSERT INTO test_invoice (id, subscription_id, period_start, period_end)
values(3, 2, '2017-01-01 00:00:00', '2017-12-01 00:00:00');
我正在使用以下内容进行更新。
UPDATE test_subscription
SET ended_at = (CASE WHEN (SELECT
MAX(period_end)
FROM test_invoice
WHERE test_subscription.id = test_invoice.subscription_id
) < now()
THEN (SELECT MAX(period_end)
FROM test_invoice
WHERE test_subscription.id = test_invoice.subscription_id
)
ELSE NULL
end),
active = (CASE WHEN (SELECT MAX(period_end)
FROM test_invoice
WHERE test_subscription.id = test_invoice.subscription_id
) < now()
THEN TRUE
ELSE FALSE
end);
答案 0 :(得分:1)
如果首先收集所有聚合,然后使用该中间结果来运行更新,则这样的更新通常会更快。关联的子查询往往要慢得多。
update test_subscription s
set ended_at = case when t.latest_end < current_timestamp then t.latest_end end,
active = t.latest_end < current_timestamp
from (
select s.id,
max(i.period_end) as latest_end
from test_subscription s
join test_invoice i on s.id = i.subscription_id
group by s.id
) t
where t.id = s.id;
答案 1 :(得分:0)
您可以将MAX
放在CASE
内
UPDATE test_subscription s
SET ( ended_at, active ) = (SELECT MAX(CASE
WHEN period_end < NOW() THEN
period_end
END),
MAX(CASE
WHEN period_end < NOW() THEN 'TRUE'
ELSE 'FALSE'
END) :: BOOLEAN
FROM test_invoice i
WHERE s.id = i.subscription_id);