Oracle 插入选择不给出 GROUP BY 表达式

Posted

技术标签:

【中文标题】Oracle 插入选择不给出 GROUP BY 表达式【英文标题】:Oracle insert select gives not a GROUP BY expression 【发布时间】:2020-10-28 14:51:06 【问题描述】:

编辑:数据库版本是 Oracle 12c

我有两个表,SRC 和 DEST,我想统计 SRC 中每个 id 的记录并将结果插入到 DEST。

这些表是使用以下脚本创建的:

CREATE SEQUENCE "ID_SEQ" INCREMENT BY 1 MAXVALUE 99999 MINVALUE 1 CACHE 20 NOORDER NOCYCLE;

CREATE TABLE "SRC_TABLE"
(
    "S_ID" NUMBER(10,0) NOT NULL,
    "SEQ" NUMBER(10,0) NOT NULL,
    "VALUE" VARCHAR2(1) NOT NULL
);

CREATE TABLE "DEST_TABLE"
(
    "D_ID" NUMBER(10,0) DEFAULT ID_SEQ.NEXTVAL NOT NULL,
    "S_ID" NUMBER(10,0),
    "CNT" VARCHAR2(1) NOT NULL,
    "PROCESS_PROG" VARCHAR2(50) NOT NULL
);

INSERT INTO SRC_TABLE VALUES (1, 1, '1');
INSERT INTO SRC_TABLE VALUES (1, 2, '1');
INSERT INTO SRC_TABLE VALUES (1, 3, '1');
INSERT INTO SRC_TABLE VALUES (2, 1, '2');
INSERT INTO SRC_TABLE VALUES (2, 2, '2');
INSERT INTO SRC_TABLE VALUES (2, 3, '2');

当我执行以下脚本时,它导致了“ORA-00979: not a GROUP BY expression”错误:

DECLARE
    PROG_NAME VARCHAR2(50) := 'DEMO';
BEGIN
    INSERT INTO DEST_TABLE (S_ID, CNT, PROCESS_PROG)
    SELECT S_ID, COUNT(*), PROG_NAME FROM SRC_TABLE
    GROUP BY S_ID;
END;

经过一些测试,我发现如果我将 PROG_NAME 替换为字符串,则脚本可以正常工作。

DECLARE
    PROG_NAME VARCHAR2(50) := 'DEMO';
BEGIN
    INSERT INTO DEST_TABLE (S_ID, CNT, PROCESS_PROG)
    SELECT S_ID, COUNT(*), 'DEMO' FROM SRC_TABLE
    GROUP BY S_ID;
END;

或者,如果我明确选择 D_ID 列的值而不是依赖于 DEFAULT 值,它也可以:

DECLARE
    PROG_NAME VARCHAR2(50) := 'DEMO';
BEGIN
    INSERT INTO DEST_TABLE (D_ID, S_ID, CNT, PROCESS_PROG)
    SELECT ID_SEQ.NEXTVAL, TMP.* FROM (
        SELECT S_ID, COUNT(*), PROG_NAME FROM SRC_TABLE
        GROUP BY S_ID
    ) TMP;
END;

我不知道为什么第一个脚本失败,但其他两个脚本有效。我做错了什么?

【问题讨论】:

【参考方案1】:

这是失败的陈述(根据你所说的):

SELECT S_ID, COUNT(*), PROG_NAME FROM SRC_TABLE
GROUP BY S_ID;

当查询中存在聚合时(在您的示例中为 count(*)),则 select 列列表中包含的所有其他未聚合的列必须包含在 group by 子句中。

那一栏是S_IDPROG_NAME 是一个局部变量,不必放入 group by 子句中。

那么,为什么您的代码失败了?不知道,因为它对我来说很好用:

SQL> DECLARE
  2      PROG_NAME VARCHAR2(50) := 'DEMO';
  3  BEGIN
  4      INSERT INTO DEST_TABLE (S_ID, CNT, PROCESS_PROG)
  5      SELECT S_ID, COUNT(*), PROG_NAME FROM SRC_TABLE
  6      GROUP BY S_ID;
  7  END;
  8  /

PL/SQL procedure successfully completed.

SQL> select * from dest_table;

      D_ID       S_ID C PROCESS_PROG
---------- ---------- - ----------------------------------------
         1          1 3 DEMO
         2          2 3 DEMO

SQL>

确定它失败了吗?您能否通过发布您自己的 SQL*Plus 会话来演示它(就像我所做的那样)?

【讨论】:

有趣。这在 dbfiddle 中的 Oracle 18 中失败了:dbfiddle.uk/… 奇怪的是,如果我在DEST_TABLE 中注释掉D_ID 列上的DEFAUT ID_SEQ.NEXTVAL 子句,错误就会消失...:dbfiddle.uk/… @GMB:因为它在 11g 中不起作用,所以我使用了数据库触发器。那么,也许它是 DEFAULT 列值,但是 - 为什么?它与 GROUP BY 有什么关系? 完全正确:为什么?!没有任何意义。

以上是关于Oracle 插入选择不给出 GROUP BY 表达式的主要内容,如果未能解决你的问题,请参考以下文章

如何使用group by 分组查询表中所有字段信息

oracle 中 select 多字段 ,但是只group by 其中某些字段

如何解决 Oracle Apex 中的“无法使用 DISTINCT、GROUP BY 等从视图中选择 FOR UPDATE”错误?

RedShift GROUP BY 常量列给出不一致的结果

oracle不可以用order by么

Oracle SQL查询到GROUP BY并减去?