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"
您可以根据 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
让我们简化一下:
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;
干杯!!
我需要提取客户的年龄并将结果细分为类别(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"
您可以根据 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
让我们简化一下:
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;
干杯!!