sql中delete嵌套的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql中delete嵌套的问题相关的知识,希望对你有一定的参考价值。

有个表,例如下表(打比方,实际表很复杂)
authorid message
1 。。。
1 。。。
1 。。。
1 。。。
2 。。。
2 。。。
message字段内容省略,我想删除发表message个数小于3的,在该表中是要删除authorid为2的,一下为实际表中的语句
delete from posts_99 where authorid in (select authorid from posts_99 group by authorid having count(message)<3)
这个语句怎么会有问题呢,怎么改都不行。高手有啥好的方法吗?
mysql中报错信息为:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'betwwen (select authorid from posts_99 group by authorid having count(message)<1' at line 1
这个语句delete from posts_99 where count(message)<10;也不行啊,烦啊
他说You can't specify target table 'posts_99' for update in FROM clause

参考技术A delete from posts_99 where authorid in (select authorid from posts_99 group by authorid having count(message)<3)
中select authorid from posts_99 group by authorid having count(message)<3
查询条件中没有count(message),所以having条件不成立。
select authorid,count(message) from posts_99 group by authorid having count(message)<3 这样的查询才成立,但在delete语句中不适用。
用两步来解决
1。将查询结果放到一个临时表中
select authorid,count(message) SL into #a from posts_99 group by authorid having count(message)<3
2.关联临时表做delete

delete from posts_99 where authorid in (select authorid from #a)本回答被提问者采纳
参考技术B delete from posts_99 where authorid in (select authorid from posts_99 group by authorid having count(authorid)<3) 参考技术C 直接用count(*)
delete from posts_99 where authorid in (select authorid from posts_99 group by authorid having count(*)<3)

在 oracle pl/sql 中如何选择嵌套类型?

【中文标题】在 oracle pl/sql 中如何选择嵌套类型?【英文标题】:How do you select into a nested type in oracle pl/sql? 【发布时间】:2013-03-22 18:24:21 【问题描述】:

我希望能够通过 rowid 删除,然后立即将要删除的数据插入到审计表中。

记录太多了 INSERT INTO ... SELECT CRITERIA 然后DELETE ... CRITERIA

我已经知道如何只使用 rowid 和 INSERT INTO ... SELECT 来做所有事情。

包体内:

TYPE some_type IS RECORD (
   row_id    ROWID,
   full_row  table_name%ROWTYPE
);
TYPE some_type_list IS TABLE OF some_type
   INDEX BY BINARY_INTEGER;

PROCEDURE do_stuff
IS
   lc_data  SYS_REFCURSOR;
   lt_recs  some_type_list;
BEGIN
   OPEN lc_date FOR
      SELECT rowid, a.*
      FROM   table_name;
   LOOP
      FETCH lc_data
      BULK COLLECT INTO lt_recs
      LIMIT 50000;
      EXIT WHEN lt_recs.COUNT = 0;
      --
      FORALL i IN lt_recs.FIRST..lt_recs.LAST
         DELETE table_name
         WHERE  ROWID = lt_recs(i).row_id;
      --
      FORALL i IN lt_recs.FIRST..lt_recs.LAST
         INSERT INTO table_name_audit VALUES lt_recs(i).full_row;
   END LOOP;
END;

如果我尝试我得到以下错误:

Line: 117 Column: 25 Type: error Text: PLS-00597: expression 'LT_RECS' in the INTO list is of wrong type

【问题讨论】:

您可能需要考虑在 BEFORE DELETE 触发器中而不是在程序逻辑中执行此操作。 不会对每次删除都进行。只有这个包。此外,触发器往往有点邪恶。最好尽可能避免。 尝试在您的过程之外声明lc_data IS CURSOR FOR SELECT ROWID, a.* FROM table_name a,然后将您的类型声明为TYPE some_type_list IS TABLE OF LC_DATA%ROWTYPE INDEX BY BINARY_INTEGER。可能值得一试。 您所说的“要插入的记录太多...选择标准然后删除...标准”到底是什么意思。 ?为什么记录数会阻止您在纯 SQL 中执行此操作? 你的表的结构是什么? 【参考方案1】:

11gR2 之前的 Oracle 版本限制我们将 BULK COLLECT 用于记录集合(嵌套表或 varray)。在 Oracle Docs 上阅读更多 here。

如果您想了解它在 11gR2 中是如何完成的,请向下滚动到此答案的 EDIT 2 部分。

另一种方法是为每一列使用单独的集合——这是一种使用最广泛的方法。在这你可以拥有:

/*
TYPE some_type IS RECORD (
   row_id    ROWID,
   full_row  table_name%ROWTYPE
);
TYPE some_type_list IS TABLE OF some_type
   INDEX BY BINARY_INTEGER;
-- */
CREATE TYPE t_row_id IS TABLE OF ROWID;
CREATE TYPE t_col1 IS TABLE OF table_name.col1%TYPE;
CREATE TYPE t_col2 IS TABLE OF table_name.col2%TYPE;
CREATE TYPE t_col3 IS TABLE OF table_name.col3%TYPE;
...
...
CREATE TYPE t_colN IS TABLE OF table_name.colN%TYPE;

PROCEDURE do_stuff
IS
   lc_data  SYS_REFCURSOR;
   -- lt_recs  some_type_list;
   row_id t_row_id;
   col1 t_col1;
   col2 t_col2;
   col3 t_col3;
   ...
   ...
   colN t_colN;
BEGIN
   OPEN lc_date FOR
      SELECT rowid, a.*
      FROM   table_name;
   LOOP
      FETCH lc_data
      BULK COLLECT INTO row_id, col1, col2, col3, ..., colN
      LIMIT 50000;
      EXIT WHEN lt_recs.COUNT = 0;
      --
      FORALL i IN row_id.FIRST..row_id.LAST
         DELETE table_name
         WHERE  ROWID = row_id(i);
      --
      FORALL i IN col1.FIRST..col1.LAST
         INSERT INTO table_name_audit VALUES (col1(i), col2(i), col3(i), ..., colN(i));
   END LOOP;
END;

为了让您了解更改,我没有删除您程序中的许多行。

编辑:请参阅我上面给出的 Oracle Docs 链接的“BULK COLLECT 限制”部分以及here。


编辑#2:


您必须使用CREATE TYPE ... IS OBJECT 而不是RECORD。此外,您需要按照我尝试的方式修改SELECT 语句。请参阅 Oracle Docs here 和 *** 问题 here 以供进一步参考。

我在我的机器(运行Oracle 11g R2)上尝试的代码如下:

-- SELECT * FROM user_objects WHERE object_type = 'TYPE'; 清屏; 设置服务器输出;

CREATE OR REPLACE TYPE temp_t_test AS OBJECT ( -- << OBJECT, not RECORD.
  test_id  INTEGER
, test_val VARCHAR2(50)
);
/

CREATE OR REPLACE TYPE temp_tbl_test AS TABLE OF TEMP_T_TEST;
/

DECLARE
  v_test TEMP_TBL_TEST;
BEGIN
  SELECT temp_t_test(t_id, t_val) -- << Notice the syntax
  -- I'm selecting the columns as the defined OBJECT type.
  BULK COLLECT INTO v_test
    FROM (SELECT 1 AS t_id, 'ABCD' AS t_val FROM dual
          UNION ALL
          SELECT 2, 'WXYZ' FROM dual
          UNION ALL
          SELECT 3, 'PQRS' FROM dual);

  dbms_output.put_line('Bulk Collect Successful!');
END;
/

** 输出**:

TYPE temp_t_test compiled
TYPE temp_tbl_test compiled
anonymous block completed
Bulk Collect Successful!

【讨论】:

谢谢,我去看看文档。 @scrappythenell:我已经编辑了答案。请检查。希望对你有用。【参考方案2】:

说实话,我认为我根本不会采用这种方法。

一种更快的方法是执行多表插入:

    将表列插入审计表,可能使用直接路径(APPEND 提示)以提高效率 将 rowid 插入到 on-commit-delete-rows 全局临时表中。

然后使用 DELETE .. WHERE ROWID IN (SELECT ORIGINAL_ROWID FROM MY_GLOBAL_TEMP_TAB) 对原始表执行删除

...然后提交。

我认为更快,代码更少。

【讨论】:

我总体上喜欢临时表的想法,但它们在大型数据集上的表现不够好。我已经在做insert into select by rowid 然后delete by rowid,所以我并不是真的在寻找替代品。我以前看过我要查找的内容,但不记得确切的语法。 如果性能没有超过基于 PL/SQL 的方法,我会感到非常惊讶——我自己从未见过大型 GTT 的问题。不过你的选择。 我们正在处理数十亿条记录。这不是很常见的音量。 音量越大,我越倾向于使用 GTT 而不是 pl/sql 方法。当然,截断或删除分区会更好,但 SQL 总是会击败 PL/SQL。 在实践中并非总是如此。特别是当您考虑多线程时。如果您只删除某些记录,您也不能截断。【参考方案3】:

您尝试在 11gR2 中工作的内容 - 您使用的是什么版本?

您帖子中唯一看起来不正确的是:

OPEN lc_date FOR
  SELECT rowid, a.*
  FROM   table_name;

应该是这样的……

OPEN lc_data FOR
  SELECT a.rowid, a.*
  FROM   table_name a;

...但这些可能只是您在清理代码以在此处发布时引入的拼写错误。

【讨论】:

以上是关于sql中delete嵌套的问题的主要内容,如果未能解决你的问题,请参考以下文章

sql嵌套删除语句

关于SQL DELETE嵌套子查询问题

SQL语句 - 嵌套查询

SQL语句 - 嵌套查询

超实用的SQL语句之嵌套查询

在 oracle pl/sql 中如何选择嵌套类型?