循环SELECT并插入记录postgres

时间:2018-01-20 00:56:48

标签: postgresql

我有一些伪代码的混合,其中包括一些PostgresSQL。我想做一个SELECT,基于这个结果集,我想循环遍历这些结果并在这个结果集中做一个嵌套循环,并从中做INSERT。关于我如何接近这一点的任何指导/建议都会很棒:

# Old CommissionExpenses do not have the cost_item_id set
# New CommissionExpenses have the cost_item_id and purchase_id set

# Find _new_ commissions
results = SELECT * FROM nok.commission_expenses ce WHERE ce.cost_item_id IS NOT NULL AND ce.purchase_id IS NOT NULL

# Loop through those and look up transactions

for result in results
  transactions = SELECT * FROM transactions t WHERE t.target_id::integer = result.purchase_id  

  for t in transactions
    INSERT INTO transactions
      nextval('transactions_id_seq'::regclass) as id,
      t.user_id,
      t.transaction_type,
      t.account,
      result.amount as amount,
      result.id as target_id,
      t.target_type,
      t.created_at,
      t.updated_at,
      t.log_id
    ;

从语法上讲我知道这是错的,但我只是想突出以上内容来表达我想要在高层次上实现的目标。我知道Postgres确实支持FOR循环,并且也尝试在下面自己执行此操作:

CREATE OR REPLACE FUNCTION loop_and_create() 

RETURNS VOID AS $$
DECLARE
  rec RECORD;
  txt RECORD;
BEGIN
  FOR rec IN EXECUTE 'SELECT * FROM nok.commission_expenses ce WHERE ce.cost_item_id IS NOT NULL AND ce.purchase_id IS NOT NULL'
    LOOP
      FOR tx IN EXECUTE 'SELECT * FROM transactions t WHERE t.target_id::integer = rec.purchase_id'
        LOOP
          INSERT INTO transactions
            nextval('transactions_id_seq'::regclass) as id,
            tx.user_id,
            tx.transaction_type,
            tx.account,
            rec.amount as amount,
            rec.id as target_id,
            tx.target_type,
            tx.created_at,
            tx.updated_at,
            tx.log_id
          ; 
        END LOOP; 
   END LOOP;
END;
$$ LANGUAGE plpgsql;

2 个答案:

答案 0 :(得分:0)

RDMS用于对集合进行操作。你不需要自己做这件事

INSERT INTO transactions (...)
SELECT t.a, t.b, ...
  FROM transactions t, nok.commission_expenses ce
 WHERE t.target_id::integer = ce.purchase_id
   AND ce.cost_item_id IS NOT NULL
   AND ce.purchase_id IS NOT NULL

答案 1 :(得分:0)

执行时

data_list

FOR tx IN EXECUTE 'SELECT * FROM transactions t WHERE t.target_id::integer = rec.purchase_id' 应该是变量。

IIRC的语法是:

rec.purchase_id

但是......这不是可行的方法:)

您真正想要的是使用FOR tx IN EXECUTE 'SELECT * FROM transactions t WHERE t.target_id = ?' USING rec. purchase_id 并使用单个语句替换您的整个函数,例如(免责声明:未对此进行测试):

insert ... select ...

它会更快(因为db执行一个查询而不是t_transactions中每行加一个)并且无比容易测试/调试(只需注释掉insert into transactions(id, user_id, transaction_type, account, amount, target_id, target_type, created_at, updated_at, log_id) select nextval('transactions_id_seq'::regclass) as id, tx.user_id, tx.transaction_type, tx.account, rec.amount as amount, rec.id as target_id, tx.target_type, tx.created_at, tx.updated_at, tx.log_id from transactions tx join nok.commission_expenses ce on ce.purchase_id = tx.target_id where ce.cost_item_id is not 行,你就可以了能够看到完全,如果要插入的查询与你期望的相符,那么。

PS:您在insert中为同一个表中的现有行插入新行似乎很可疑......您确定不想更新吗?改为现有的行?