有没有更好的方法来更新PostgreSQL

时间:2018-06-21 22:00:37

标签: postgresql sql-update

当最大ended_at未通过时,我正在尝试更新active表中的test_subscriptionperiod_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);

2 个答案:

答案 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;   

在线示例:http://rextester.com/NMMF41667

答案 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); 

Demo