简体   繁体   English

带案例表达的“不是单组分组函数”

[英]“not a single-group group function” with case expression

I get error "ORA-00937: not a single-group group function" when I try to use a case expression: 尝试使用case表达式时,出现错误“ ORA-00937:不是单组分组函数”:

SELECT  CASE 
   WHEN EXTRACT_TABLE IS NOT NULL 
   THEN 
  'SELECT '||LISTAGG((EXTRACT_TABLE||'.'||EXTRACT_COLONNE ||' AS " '|| EXTRACT_LIBELLE || ' " '),',') WITHIN GROUP(ORDER BY EXTRACT_ORDRE)
   ELSE 'SELECT '||LISTAGG((EXTRACT_COLONNE ||' AS " '|| EXTRACT_LIBELLE || ' " '),',') WITHIN GROUP(ORDER BY EXTRACT_ORDRE)
    END

It works OK without the case expression, as: 它不带大小写表达式就可以正常工作,例如:

SELECT
  'SELECT '||LISTAGG((EXTRACT_TABLE||'.'||EXTRACT_COLONNE ||' AS " '|| EXTRACT_LIBELLE || ' " '),',') WITHIN GROUP(ORDER BY EXTRACT_ORDRE)

But I really need to check if EXTRACT_TABLE is null or not. 但是我真的需要检查EXTRACT_TABLE是否为null。 How can I fix this? 我怎样才能解决这个问题?

Thanks 谢谢

Use CASE inside LISTAGG : LISTAGG内使用CASE

WITH sample AS (SELECT 1 AS EXTRACT_ORDRE, 'tab1' AS EXTRACT_TABLE, 'col1' AS EXTRACT_COLONNE, 'name1' AS EXTRACT_LIBELLE FROM DUAL
                    UNION ALL
                    SELECT 2, 'tab2', 'col2', 'name2' FROM DUAL
                    UNION ALL
                    SELECT 3, NULL, 'col3', 'name3' FROM DUAL
                    )
    select 'SELECT '||LISTAGG(CASE WHEN EXTRACT_TABLE IS NOT NULL THEN (EXTRACT_TABLE||'.'||EXTRACT_COLONNE ||' AS " '|| EXTRACT_LIBELLE || ' " ') 
                ELSE EXTRACT_COLONNE ||' AS " '|| EXTRACT_LIBELLE || ' " ' END ,',') WITHIN GROUP(ORDER BY EXTRACT_ORDRE) AS result
    from sample;

Output: 输出:

RESULT
-------------------
SELECT tab1.col1 AS " name1 " ,tab2.col2 AS " name2 " ,col3 AS " name3 "

The error means you need to include extract_table in your group-by clause; 该错误意味着您需要在group-by子句中包含extract_table or add a group-by if you don't have one already, which might involve identifying other columns, and could affect the output. 或添加分组依据(如果您还没有),这可能涉及识别其他列,并可能影响输出。 It depends on the rest of your query and the data, and the result you expect. 它取决于查询的其余部分和数据以及预期的结果。

Your original non-case approach leaves unwanted periods in the output. 您原来的非案例方法会在输出中留下不需要的时间段。 As an example, with a CTE for some sample data, your query gives: 例如,对于一些示例数据,使用CTE,您的查询将给出:

-- CTE for sample data
with cte (extract_table, extract_colonne, extract_libelle, extract_ordre) as (
  select null, 'col1', 'label1', 2 from dual
  union all
  select 'tab42', 'col2', 'label2', 3 from dual
  union all
  select 'tab42', 'col3', 'label3', 1 from dual
)
-- actual query
SELECT
  'SELECT '||LISTAGG((EXTRACT_TABLE||'.'||EXTRACT_COLONNE ||' AS " '|| EXTRACT_LIBELLE || ' " '),',') WITHIN GROUP(ORDER BY EXTRACT_ORDRE)
from cte;

SELECT tab42.col3 AS " label3 " ,.col1 AS " label1 " ,tab42.col2 AS " label2 "

Your case-expression approach, with an added group by EXTRACT_TABLE clause, would split that data into two results: 您的case-expression方法( group by EXTRACT_TABLE子句添加了group by EXTRACT_TABLE会将数据分成两个结果:

-- CTE for sample data
with cte (extract_table, extract_colonne, extract_libelle, extract_ordre) as (
  select null, 'col1', 'label1', 2 from dual
  union all
  select 'tab42', 'col2', 'label2', 3 from dual
  union all
  select 'tab42', 'col3', 'label3', 1 from dual
)
-- actual query
SELECT 
  CASE 
     WHEN EXTRACT_TABLE IS NOT NULL THEN 
      'SELECT '||LISTAGG((EXTRACT_TABLE||'.'||EXTRACT_COLONNE ||' AS " '|| EXTRACT_LIBELLE || ' " '),',') WITHIN GROUP(ORDER BY EXTRACT_ORDRE)
     ELSE 
       'SELECT '||LISTAGG((EXTRACT_COLONNE ||' AS " '|| EXTRACT_LIBELLE || ' " '),',') WITHIN GROUP(ORDER BY EXTRACT_ORDRE)
  END
from cte
group by EXTRACT_TABLE;

SELECT tab42.col3 AS " label3 " ,tab42.col2 AS " label2 " 
SELECT col1 AS " label1 " 

which probably isn't what you want. 这可能不是您想要的。 However, if you actually have a filter and are sure that all selected rows either have or do not have a table name - and not a mix as above - then this would still work too. 但是,如果您实际上有一个过滤器,并确保所有选定的行都具有或不具有表名-而不是上面的混合表-那么这仍然可以使用。

Another approach is to just skip the table name, or more importantly the . 另一种方法是只跳过表名,或更重要的是. that separates the table and column names, further into the query; 将表名和列名分开,进一步进入查询; ie conditionally skip that period by replacing '.' 即通过替换'.'有条件地跳过该时间段'.' with CASE WHEN EXTRACT_TABLE IS NOT NULL THEN '.' CASE WHEN EXTRACT_TABLE IS NOT NULL THEN '.' . When that column is null there will be no name part anyway, and that expression will suppress the period, so you only get the column name. 当该列为null时,无论如何将没有名称部分,并且该表达式将取消句点,因此您仅获得列名称。

SELECT
  'SELECT ' || LISTAGG((EXTRACT_TABLE
    || CASE WHEN EXTRACT_TABLE IS NOT NULL THEN '.' END
    || EXTRACT_COLONNE || ' AS " ' || EXTRACT_LIBELLE || ' " '), ',')
  WITHIN GROUP(ORDER BY EXTRACT_ORDRE)

With the same sample data that gets a single row, without the invalid leading period: 对于具有单行的相同样本数据,没有无效的前置时间:

-- CTE for sample data
with cte (extract_table, extract_colonne, extract_libelle, extract_ordre) as (
  select null, 'col1', 'label1', 2 from dual
  union all
  select 'tab42', 'col2', 'label2', 3 from dual
  union all
  select 'tab42', 'col3', 'label3', 1 from dual
)
-- actual query
SELECT
  'SELECT ' || LISTAGG((EXTRACT_TABLE
    || CASE WHEN EXTRACT_TABLE IS NOT NULL THEN '.' END
    || EXTRACT_COLONNE || ' AS " ' || EXTRACT_LIBELLE || ' " '), ',')
  WITHIN GROUP(ORDER BY EXTRACT_ORDRE)
from cte;

SELECT tab42.col3 AS " label3 " ,col1 AS " label1 " ,tab42.col2 AS " label2 " 

This is your query: 这是您的查询:

SELECT (CASE WHEN EXTRACT_TABLE IS NOT NULL 
             THEN <expression with LISTAGG()>
             THEN <expression with LISTAGG()>
        END)
FROM t;

Because of the LISTAGG() , this is an aggregation query. 由于LISTAGG() ,这是一个聚合查询。 However, there is no GROUP BY . 但是, 没有 GROUP BY In such a case, all column references need to be arguments to aggregation functions. 在这种情况下, 所有列引用都必须是聚合函数的参数。

I assume you mean one of these: 我认为您的意思是以下之一:

SELECT (CASE WHEN EXTRACT_TABLE IS NOT NULL 
             THEN <expression with LISTAGG()>
             THEN <expression with LISTAGG()>
        END)
FROM t
GROUP BY EXTRACT_TABLE;

Or: 要么:

SELECT <expression with LISTAGG()>
FROM t
WHERE EXTRACT_TABLE IS NOT NULL
UNION ALL
SELECT <expression with LISTAGG()>
FROM t
WHERE EXTRACT_TABLE IS NULL;

It is also possible that you intend conditional aggregation: 您可能还打算进行条件聚合:

SELECT 'SELECT '|| LISTAGG((EXTRACT_TABLE || '.' || col_lib ||'  AS " '|| EXTRACT_LIBELLE || ' " '), ',') WITHIN GROUP(ORDER BY EXTRACT_ORDRE)
FROM (SELECT (CASE WHEN EXTRACT_TABLE IS NOT NULL 
                   THEN EXTRACT_COLONNE
                   ELSE EXTRACT_LIBELLE
              END) as col_lib
             t.*
      FROM t
     ) t

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM