Oracle SQL 中的案例表达式(Pentaho 报表设计器)

Case Expressions in Oracle SQL (Pentaho Report Designer)

我需要提取客户的年龄并将结果细分为类别(18-21、22-35、36-50 等)。

使用基于 Oracle 的 Pentaho Report Designer。

我可以计算特定年龄,但希望计数反映年龄范围,而不是单个年龄。尝试通过 case 语句完成此操作但不断出错。

最少 SQL 曝光,Pentaho/Oracle 新手,本网站新手。

--SQL 年龄和计数。

SELECT COUNT(*), "CLIENT_TABLE"."AGE"
FROM "CLIENT_TABLE"
GROUP BY "CLIENT_TABLE"."AGE"
ORDER BY "CLIENT_TABLE"."AGE"

--这是我的CASE表达式。

CASE
    WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
    WHEN "CLIENT_TABLE"."AGE" > 18 AND <= 21 THEN '19 - 21'
    WHEN "CLIENT_TABLE"."AGE" > 21 AND <= 35 THEN '22 - 35'
END AS Age

我已将 CASE 表达式放在 SELECT 和 WHERE 子句中,但不断收到这两条错误消息... "FROM keyword not found where expects" & "Missing expression".

更新后的代码产生错误,"not a Group By Expression."

SELECT COUNT(*),
      (CASE
        WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
        WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '18 - 21'
        WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
        WHEN "CLIENT_TABLE"."AGE" <= 50 THEN '36 - 50'
        WHEN "CLIENT_TABLE"."AGE" <= 64 THEN '51 - 64'
        WHEN "CLIENT_TABLE"."AGE" >= 65 THEN '65+'
       END) AS AgeRange
FROM "CLIENT_TABLE"
GROUP BY (CASE
        WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
        WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '18 - 21'
        WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
        WHEN "CLIENT_TABLE"."AGE" <= 50 THEN '36 - 50'
        WHEN "CLIENT_TABLE"."AGE" <= 64 THEN '51 - 64'
        WHEN "CLIENT_TABLE"."AGE" >= 65 THEN '65+'
       END)
ORDER BY "CLIENT_TABLE"."AGE"

我想你想要:

SELECT COUNT(*),
       (CASE WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
             WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '19 - 21'
             WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
        END) AS Age
FROM "CLIENT_TABLE"
GROUP BY (CASE WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
               WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '19 - 21'
               WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
           END)
ORDER BY "CLIENT_TABLE"."AGE"

备注:

  • 在Oracle中,需要重复GROUP BY中的表达式。
  • 我简化了 case 表达式中条件的逻辑。条件按顺序求值。
  • 在这样做时,18 岁的孩子也被包括在内——现在在 '19 - 21' 组中。将它们包括在某个地方似乎比将它们放在 NULL 组中更合适。

根据@Gordon 的回答,您的 'updated code' 得到 "ORA-00979: not a GROUP BY expression",因为您尝试按 "CLIENT_TABLE"."AGE" 订购 - 而该列不在 GROUP BY 中条款。你可能想要:

ORDER BY MIN("CLIENT_TABLE"."AGE")

但是,这只会向您显示具有匹配数据的范围。如果您想查看所有范围,包括零计数,您可以将范围生成为内联视图或 CTE 和外部连接到您的真实数据,例如:

WITH "RANGES" ("MIN_AGE", "MAX_AGE", "LABEL") AS (
  SELECT 0, 17, 'Under 18' FROM "DUAL"
  UNION ALL
  SELECT 18, 21, '18 - 21' FROM "DUAL"
  UNION ALL
  SELECT 22, 35, '22 - 35' FROM "DUAL"
  UNION ALL
  SELECT 36, 50, '36 - 50' FROM "DUAL"
  UNION ALL
  SELECT 51, 64, '51 - 64' FROM "DUAL"
  UNION ALL
  SELECT 65, NULL, '65+' FROM "DUAL"
)
SELECT COUNT("CLIENT_TABLE"."AGE"),
       "RANGES"."LABEL" AS AgeRange
FROM "RANGES"
LEFT JOIN "CLIENT_TABLE"
ON "CLIENT_TABLE"."AGE" >= "RANGES"."MIN_AGE"
AND ("RANGES"."MAX_AGE" IS NULL OR "CLIENT_TABLE"."AGE" <= "RANGES"."MAX_AGE")
GROUP BY "RANGES"."MIN_AGE", "RANGES"."LABEL"
ORDER BY "RANGES"."MIN_AGE"

db<>fiddle

您可以根据 min/max 年龄生成标签,甚至可以只根据最小年龄生成标签(使用 lead 找到最大值),您还可以探索其他变体。

(我假设您有大写和带引号的标识符是有原因的,可能是您的报告工具的要求——我知道有些奇怪的事情确实需要它们;但从 Oracle 的角度来看,双引号不是需要,我个人觉得小写或混合代码(也许关键字大写)更容易阅读。您可能还想使用 table 别名。)


I should have an ELSE in the CASE for null values.

COUNT() 忽略空值,因此如果这些为空值,COUNT("CLIENT_TABLE"."AGE") 将 return 归零。您需要计算 table 中的任何非空列; RANGES CTE 中需要另一个虚拟行,并修改逻辑以包含未设置年龄的行;例如:

with ranges (min_age, max_age, label) as (
  select 0, 17, 'Under 18' from dual
  union all
  select 18, 21, '18 - 21' from dual
  union all
  select 22, 35, '22 - 35' from dual
  union all
  select 36, 50, '36 - 50' from dual
  union all
  select 51, 64, '51 - 64' from dual
  union all
  select 65, null, '65+' from dual
  union all
  select null, null, 'Unknown' from dual
)
select count(client_table.id), -- count any not-null column from this table
       ranges.label as agerange
from ranges
left join client_table
on ((ranges.min_age is null and client_table.age is null)
  or client_table.age >= ranges.min_age)
and (ranges.max_age is null or client_table.age <= ranges.max_age)
group by ranges.min_age, ranges.label
order by ranges.min_age

db<>fiddle

让我们简化一下:

SELECT AGERANGE, COUNT(1) AS CNT FROM
SELECT (CASE
        WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
        WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '18 - 21'
        WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
        WHEN "CLIENT_TABLE"."AGE" <= 50 THEN '36 - 50'
        WHEN "CLIENT_TABLE"."AGE" <= 64 THEN '51 - 64'
        WHEN "CLIENT_TABLE"."AGE" >= 65 THEN '65+'
       END) AS AgeRange
FROM "CLIENT_TABLE")
GROUP BY AGERANGE
ORDER BY CASE AGERANGE
WHEN 'Under 18' THEN 1 
WHEN '18 - 21' THEN 2
WHEN '22 - 35' THEN 3
WHEN '36 - 50' THEN 4
WHEN '51 - 64' THEN 5
WHEN '65+' THEN 6 
ELSE 7 END;

干杯!!