【问题标题】:How to use GROUP BY on a CLOB column with Oracle? [duplicate]如何在 Oracle 的 CLOB 列上使用 GROUP BY?
【发布时间】:2014-01-07 20:31:41
【问题描述】:

我正在尝试将 GROUP BY 函数与 Oracle 中的 MAX 结合起来。我阅读了很多文档,试图弄清楚如何通过 Oracle 格式化我的请求总是返回:

ORA-00979:“不是按表达式分组”

这是我的要求:

SELECT A.T_ID, B.T, MAX(A.V) 
FROM bdd.LOG A, bdd.T_B B
WHERE B.T_ID = A.T_ID
GROUP BY A.T_ID
HAVING MAX(A.V) < '1.00';

有什么建议吗?

编辑我的字段的数据类型似乎有些棘手。

  • T_IDVARCHAR2
  • A.VVARCHAR2
  • B.TCLOB

【问题讨论】:

  • 不要将苹果(数字)与橙子(字符串)进行比较。 '1.00' 是一个字符串,它不是是一个数字 -(1.001)是一个数字。
  • @a_horse_with_no_name 你说得对,现在好多了 :) 但我仍然遇到 932 错误,看起来像 oracle 期望的一些数据类型并得到一个 CLOB insteab - 这是 B.T 的类型
  • 您不能在CLOB 列上创建group by - 为什么需要它?如果你需要一个 max() 那么CLOB 听起来不像是正确的数据类型。如果您将数字存储在LOG.V 中,那么为什么不将其定义为number?。在varchar 列中存储数字是一个非常糟糕的设计。
  • A.V 不是 CLOB,只有 B.T 是 :) 我知道糟糕的设计不是我的,我暂时无法更改
  • 为什么我知道你的回答是“这不是我的设计,我无法改变它”。显然没有人创建过这样的表,但几乎每个人都必须使用它们——这是数据库设计的一个谜。

标签: sql oracle group-by max


【解决方案1】:

我非常熟悉为其他人设计的表编写查询以执行与您想要的几乎完全不同的事情的现象。当我遇到同样的问题时,我已经使用过。

GROUP BY TO_CHAR(theclob)

当然你也必须TO_CHAR输出中的 clob。

请注意,这个问题有 2 个级别...第一个是您有一个不需要是 clob 的 clob 列;它只包含一些适合VARCHAR2 的小字符串。我的解决方法适用于此。

第二级是您实际上想要按包含大字符串的列进行分组。在这种情况下,TO_CHAR 可能无济于事。

【讨论】:

  • 如果 clob 超过 4000 个字符,则不起作用。
【解决方案2】:

试试这个:

SELECT A.T_ID, B.T, MAX(A.V) 
FROM bdd.LOG A, bdd.T_B B
WHERE B.T_ID = A.T_ID
GROUP BY A.T_ID, B.T
HAVING MAX(A.V) < 1;

【讨论】:

  • 它返回另一个错误:ORA-00932 数据类型不一致。是指上面的评论吗?
  • @x_vi_r 是的,应该是。我已经更新了答案检查它
  • 仍然得到 932 错误,正如我上面所说的 A.V 是 VARCHAR2
  • @x_vi_r 尝试转换为浮点数或十进制或整数
【解决方案3】:

经过一些修复后,主要问题似乎出在group by

您必须在SELECTGROUP BY 中使用相同的表

我也只取了 CLOB 的一个子字符串来让它工作。工作要求是:

    SELECT TABLE_A.ID,
       TABLE_A.VA,
       B.TRACE
FROM
(SELECT A.T_ID ID,
          MAX(A.V) VA
   FROM BDD.LOG A
   GROUP BY A.T_ID HAVING MAX(A.V) <= '1.00') TABLE_A,
                                                                BDD.T B
WHERE TABLE_A.ID = B.T_id;

【讨论】:

    【解决方案4】:

    这个响应有点晚了,但是对于那些需要分组值和最大标准列之外的值的人,您可以在分区上使用 ROW_NUMBER() 来获得您想要的:

    SELECT T_ID, T, V
    FROM 
    (
     SELECT A.T_ID, B.T, A.V, ROW_NUMBER() OVER (PARTITION BY A.T_ID ORDER BY to_number(A.V) DESC) rownumber
     FROM bdd.LOG A, bdd.T_B B
     WHERE B.T_ID = A.T_ID
    )
    WHERE rownumber = 1
    

    不要忘记 ORDER BY 上的 DESC 修饰符以获得最大值;没有它,您将获得最小值。如果 A.V 可以为空,您还需要将其包装在 NVL() 中,否则您只会得到 NULL;无论您选择升序还是降序,NULL 值始终排在第一位(至少在 Oracle SQL 中是这样)。

    【讨论】:

      【解决方案5】:

      如果可能,您可以将 clob 转换为 PK,而不是转换为 PK 上的选择。根据执行计划,这甚至比 rowid 更快。在这种情况下,我需要第一个不为空的 clob。所以我说如果 clob 不为空,请使用 pk else null。结果不是 clob,我可以在外部查询中获取 clob。

      select a.* ,r.DESCRIPTION 
      from (
      select distinct
      FIRST_VALUE(
        case 
           when a.DESCRIPTION is null then null 
           else PK_COL 
        end 
        IGNORE NULLS) 
        OVER (ORDER BY a.sort_col desc ROWS between UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) DESCRIPTION_PK, 
      group_column
      from reporting a where group_column='xyz) a
      join reporting r on (r.PK_COL=a.DESCRIPTION_PK);
      

      【讨论】:

        【解决方案6】:

        这并不能解决 OP 的问题,但在某些情况下可能会有所帮助。

        让我们拥有

        CREATE TABLE "TEST" (   
          ID NUMBER, 
          DATA CLOB
        );
        

        如果实际的 CLOB 数据不超过 4000 个字符,我们可以使用 TO_CHAR 将其转换为 VARCHAR32,然后进行我们需要的分组:

        SELECT 
          DATA_AS_CHAR,
          COUNT(*)
        FROM
        (
          SELECT
            ID,
            TO_CHAR(DATA) DATA_AS_CHAR
          FROM TEST
        )
        GROUP BY
          DATA_AS_CHAR;
        

        如果超过,我们必须应用一些启发式方法,例如子串前 4000 个字符:

        SELECT 
          DATA_AS_CHAR,
          COUNT(*)
        FROM
        (
          SELECT
            ID,
            TO_CHAR(DBMS_LOB.SUBSTR(DATA, 4000)) DATA_AS_CHAR
          FROM TEST
        )
        GROUP BY
          DATA_AS_CHAR;
        

        与任何其他散列技术一样,这可能会导致冲突(组数少于预期)。

        【讨论】:

          【解决方案7】:
          WITH foo as (
            SELECT A.T_ID, B.T, MAX(A.V) maxav
            FROM bdd.LOG A, bdd.T_B B
            WHERE B.T_ID = A.T_ID
            GROUP BY A.T_ID, B.T
          )
          SELECT * FROM foo WHERE maxav < 1
          

          【讨论】:

          • 感谢您的帮助!与以前相同的错误:ORA-00932 预期数据类型不一致:- 得到 CLOB。 (CLoB 是 B.T 的数据类型)
          • 那么显然,按 CLOB 列分组是个坏主意。
          • 我应该使用 DBMS_LOB 吗?
          • 您应该重新考虑您的查询设计。 LOB 列并不意味着被分组。一种方法是从选择和分组依据中排除您的 LOB 列,然后使用子选择为您已经分组的行选择适当的 LOB 值。不过,糟糕的设计。
          猜你喜欢
          • 2021-11-06
          • 1970-01-01
          • 1970-01-01
          • 2011-01-26
          • 1970-01-01
          • 2019-12-02
          • 1970-01-01
          • 2012-03-08
          • 1970-01-01
          相关资源
          最近更新 更多