Teradata:分析函数中Case语句的使用问题及解决方法咨询
SQL错误原因分析与解决方案
错误原因
- 分组规则违反:SQL使用
GROUP BY id,但SELECT列表中的id||date、窗口函数依赖的date、strtdate等字段既没被聚合函数包裹,也不在GROUP BY子句中,直接触发“Non-aggregate columns must be part of the associated group”错误——分组查询要求所有非聚合列必须出现在GROUP BY里。 - 窗口函数语法错误:最后一个窗口函数的
partition by部分缺少逗号,正确写法应为partition by id,date order by strtdate desc,当前写法属于语法错误。 - 逻辑不符合需求:用
max(loanamt)获取Initial Balance是错误的,需求是取每个(id,date)组合的第一个值,而max取的是最大值,和需求不匹配。
实现思路
- 移除多余的GROUP BY:窗口函数本身可按
id,date分区计算,无需额外分组,避免分组规则冲突。 - 用正确窗口函数取初始值:通过
first_value(loanamt) over(partition by id, date order by strtdate)获取每个(id,date)分组下最早的loanamt,作为Initial Balance。 - 精准提取指定日期余额:针对Opening Balance(2018-12-01)和Closing Balance(2018-12-31),用CASE语句筛选对应日期的balamt,再通过窗口函数在分区内提取该值(每个(id,date)分区内指定日期的快照记录唯一)。
- 去重得到唯一结果:窗口函数会给每一行生成相同的分区计算结果,最后用
DISTINCT去重,得到每个(id,date)组合的唯一汇总记录。
修正后的SQL示例
SELECT DISTINCT id||date AS ID, first_value(loanamt) OVER(PARTITION BY id, date ORDER BY strtdate) AS Initial_balance, max(CASE WHEN strtdate = '2018-12-01' THEN balamt ELSE NULL END) OVER(PARTITION BY id, date) AS Opening_balance, max(CASE WHEN strtdate = '2018-12-31' THEN balamt ELSE NULL END) OVER(PARTITION BY id, date) AS Closing_balance FROM tab WHERE id = 'ABC';
若你的SQL支持FILTER子句(如PostgreSQL),可简化为:
SELECT DISTINCT id||date AS ID, first_value(loanamt) OVER(PARTITION BY id, date ORDER BY strtdate) AS Initial_balance, max(balamt) FILTER(WHERE strtdate = '2018-12-01') OVER(PARTITION BY id, date) AS Opening_balance, max(balamt) FILTER(WHERE strtdate = '2018-12-31') OVER(PARTITION BY id, date) AS Closing_balance FROM tab WHERE id = 'ABC';
内容的提问来源于stack exchange,提问作者user2653353
相关产品推荐
相关产品推荐

