如何将列值从存储过程中的另一个表更新到表中?

Posted

技术标签:

【中文标题】如何将列值从存储过程中的另一个表更新到表中?【英文标题】:How to update column value to a table from another table in a stored procedure? 【发布时间】:2019-09-29 00:05:33 【问题描述】:

我创建了一个程序,通过查询包括事务 tbl 在内的其他表来结算所有事务记录,并自动标记参考号和日期。

我尝试做的是我的settle_transaction 过程需要从所选语句生成我的查询并将它们插入到结算表中。同时,我还需要update ref_num 和处理日期作为事务表的“标记”,这样我在再次调用过程时就不会重复结算。否则,我不知道如何停止显示相同的结算数据两次

这里是输出一个结算tbl的过程和类似下面的结构:

BEGIN
    for r_client in 
    (
        select clientid,
        client_name, sum(transaction) total_amount
        from transaction_tbl tran join terminal_tbl term
        on tran.terminalid = term.terminalid join client_tbl c on c.clientid = term.clientid
        where refnr is null
    )
    loop
    v_refnr := get_refnr;
        insert into settlement_tbl
        (
            Ref_Num, 
            Total,
            CLIENTID,
            TITLE, 
            processeddate
        )
        values (v_refnr, total_amount, clientid,
        name,sysdate);
update_refnr(v_refnr, sysdate)
        end loop;
END

输出:

| reference_num | total amount | client id | client name | processed_date |
|---------------|--------------|-----------|-------------|----------------|

当我执行上述过程时,它会填充来自选择查询的所有结果。但是,如果我再次执行,它将重复相同的结果,尤其是总金额。

我正在寻找一种解决方案,将另一个过程/函数放入此结算过程中,以防止此过程中所选查询的重复记录。

我使用ref. no#process_date 将现有的参考编号和日期更新为下面显示的事务tbl。

| transaction_num | transaction amount | reference_num | processed_date |
|-----------------|--------------------|---------------|----------------|

这是我在结算过程中尝试的代码,但仍然显示重复记录,无法更新到交易表。

procedure update_refnr(
  p_refnr in number,
  p_processeddate in date
)
is
begin
    UPDATE TRANSACTION t 
       SET t.refnr = p_refnr
     WHERE EXISTS (SELECT p_processeddate 
                     FROM terminal_tbl
                    WHERE t.TERMINALID= term.TERMINALID
                      AND t.processeddate = p_processeddate
                      AND t.refnr IS NULL);   
--exception handling below

end update_refnr;

我也尝试了其他 SQL reference 但无法编译。

理想情况下,当我从存储过程中检索每条记录时,我的结算 tbl 中没有重复记录。

【问题讨论】:

我不确定我是否完全理解您的问题,为什么不修复原始程序,以免产生重复?您在示例和代码中使用了不同的列名或别名,因此很难遵循。也许在问题中添加一些示例数据 因为交易一直在运行,所以我做一个结算表,随时从每个客户端生成一个总金额,否则,它会再次执行之前的交易。希望你能理解我的问题。 不确定,第一个过程是否只是一个选择查询? 看起来您正在该过程中执行 INSERT 而不仅仅是 SELECT。 您是否尝试过使用Merge。你的问题陈述在我看来更像Merge 【参考方案1】:

您只想在新数据不存在时将其插入到您的表中。正如其他人所说,您可以使用 MERGE 来做到这一点:

BEGIN
  for r_client in (select clientid,
                          client_name,
                          sum(transaction) total_amount
                     from transaction_tbl tran
                     join terminal_tbl term
                       on tran.terminalid = term.terminalid
                     join client_tbl c
                       on c.clientid = term.clientid
                     where refnr is null)
  loop
    v_refnr := get_refnr;

    MERGE INTO settlement_tbl s
      USING (SELECT v_refnr      AS REF_NUM,
                    total_amount AS TOTAL,
                    clientid     AS CLIENTID,
                    name         AS TITLE,
                    SYSDATE      AS PROCESSEDDATE
               FROM DUAL) d
        ON (s.REF_NUM = d.REF_NUM)
      WHEN NOT MATCHED THEN
        INSERT (Ref_Num,   Total,   CLIENTID,   TITLE,   processeddate)
        VALUES (d.REF_NUM, d.TOTAL, d.CLIENTID, d.TITLE, d.PROCESSEDDATE);

    update_refnr(v_refnr, sysdate);
  END LOOP;
END;

WHEN NOT MATCHED 在您的表中不存在v_refnr 时插入新数据。

祝你好运。

【讨论】:

我不仅要向结算表插入新数据,还要将 ref_num 和处理日期链接回我最初从每笔交易中生成总金额的交易表,这样我就可以看到哪个交易已经结算,避免与该 ref_num 重复。 我得到了这个Error(22,17): PL/SQL: ORA-00904: "name": invalid identifier的客户名称 在您使用的原始代码中 name - 我只是从那里复制了它。你的意思是client_name吗? 是的,我听从了你的建议并得到了上述错误,是那个别名导致了这个问题吗? 我想知道为什么在这种情况下使用 dual 而不是 r_client 记录?

以上是关于如何将列值从存储过程中的另一个表更新到表中?的主要内容,如果未能解决你的问题,请参考以下文章

Redshift中的存储过程将数据加载到表中

基于列值从存储过程调用视图

CodeIgniter 查询:如何将列值移动到同一行中的另一列并将当前时间保存在原始列中?

如果上一列值不为空,则更新表中的下一列

使用 sqlbulktools 更新表时对列值求和

如何获取一个表标识列值以及如何在存储过程中使用该值