【问题标题】:How to delete records and return them in one statement? SQL/Java如何删除记录并在一个语句中返回它们? SQL/Java
【发布时间】:2017-05-05 23:06:32
【问题描述】:

我很难弄清楚这一点。我知道必须有办法做到这一点,而且我可能非常接近(或者可能不是)。我想从表中删除一组记录并返回在一个语句中删除的记录。该表是一个队列,我需要从中弹出一些记录。

这可以通过 2 个语句完成工作:

select id, add_date from my_queue where rownum <= 10;
-- save for processing
delete from my_queue where rownum <= 10;

如何将这些组合成 1 条语句,然后在 Java 中读取结果?

我查看了this SO question,并尝试在问题中实现这两种方法,但是,在我的情况下,我有 2 列要输出,我需要使用 bulk collect into 子句,因此输出将成为一张桌子。这样做,我无法弄清楚我需要做什么才能正确定义和注册输出以执行匿名 PL/SQL 语句。

这是我最接近的尝试:

StringBuilder sql = new StringBuilder();
sql.append("BEGIN ");
sql.append("  delete from my_queue where rownum <= 10 ");
sql.append("  returning _id into ?; ");
sql.append("END; ");

CallableStatement cstmt = con.prepareCall(sql.toString());
cstmt.registerOutParameter(1, OracleTypes.CURSOR);
//cstmt.registerOutParameter(1, OracleTypes.NUMBER);
//cstmt.registerOutParameter(1, OracleTypes.ARRAY);

cstmt.execute(); // throws error, see comments below

以下是根据注册的输出类型执行时的各种错误:

使用光标:ORA-00932: inconsistent datatypes: expected CURSER got NUMBER

使用号码:ORA-01422: exact fetch returns more than requested number of rows

使用数组:ORA-03115: unsupported network datatype or representation

【问题讨论】:

  • 为什么不在开始/结束块中的删除语句之前运行选择语句?
  • @Sebas - 这会阻止同一张表上的其他操作吗?即如果选择运行,其他一些操作插入,然后删除运行......其他操作会在插入之前等待 PL/SQL 块完成吗?
  • Select 语句不锁定。有关 DML 操作是否包含锁定的更多信息,请参见此处:docs.oracle.com/cloud/latest/db112/SQLRF/…
  • 好的,所以真正的问题不是“我怎样才能在一个语句中完成所有操作”。相反,它是“我如何删除十行并在 SELECT 查询中显示它们 - 并确保它是相同的行,即使表上还有其他事务。”您不能在一个声明中完成所有操作; SQL 中没有组合的 SELECT/DELETE 语句。确切的要求是什么也不清楚。如果您确定了 10 行,但在您要删除时,有 3 行已经被另一个用户删除了怎么办?删除其他七个可以吗?
  • 一旦您打开事务,任何东西都无法改变您对表中内容的看法。你安全了。这是它的全部意义。这也意味着如果您的删除语句(或从另一个请求完成的)将阻止您的事务,直到它完成。这不一定是问题,只需确保查询已优化即可。

标签: java sql oracle plsql oracle11g


【解决方案1】:

我结合了几个不同帖子/网站的解决方案,并使用bulk collect into 子句提出了一个可行的解决方案:

create or replace type queue_record as object (
  id number(10),
  add_date date
);

create or replace type my_queue_type as table of queue_record;

create or replace procedure pull_from_queue (
  pull_size in number,
  pulled_records out sys_refcursor
)
is
  tbl my_queue_type;
begin

  delete from my_queue
  where id in (
    select id from ( select * from my_queue order by add_date )
    where rownum <= pull_size
  )
  returning queue_record(id, add_date)
  bulk collect into tbl;

  open pulled_records for
  select * from table(cast(tbl as my_queue_type)) order by add_date;

end pull_from_queue;

【讨论】:

  • 对于那些不赞成投票的人,请告诉我这个解决方案是不正确的并且没有回答原始问题。
【解决方案2】:

您可以plsql 关联数组来存储选定的数据并从表中删除您的记录。这是 pl/SQL 示例。

/* Formatted on 12/20/2016 3:45:29 PM (QP5 v5.277) */
DECLARE
   TYPE type_rec IS RECORD
   (
      Employee_id     NUMBER,
      Employee_name   VARCHAR2 (30)
   );

   TYPE type_aa IS TABLE OF type_rec
      INDEX BY PLS_INTEGER;

   l_var1   type_aa;
BEGIN
   FOR loop_aa IN (SELECT ROWNUM rn, Employee_id, Employee_name
                     FROM employees                
                  )
   LOOP
      l_var1 (loop_aa.rn).Employee_id := loop_aa.Employee_id;
      l_var1 (loop_aa.rn).Employee_name := loop_aa.Employee_name;
      DBMS_OUTPUT.put_line (
            'Employee ID: '
         || loop_aa.Employee_id
         || ', Employee Name: '
         || loop_aa.Employee_name);
   END LOOP loop_aa;

   -- Delete records here
  DELETE FROM employees;
  --Commit;

END;
/

【讨论】:

    猜你喜欢
    • 2019-03-05
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-13
    相关资源
    最近更新 更多