Oracle查询如何按每13周间隔为每位用户调用自定义函数
现有实现存在的问题
- 标量子查询返回多行报错:你在SELECT列表中写的子查询会对每个用户返回多条周期记录,Oracle不允许标量子查询返回多行,执行时会直接抛出
ORA-01427: 单行子查询返回多个行错误。 - 日期计算逻辑不符合需求:你当前子查询返回的
fin实际是每个周期的起始日期,而非你期望的周期结束日期,同时你期望的周期是91天跨度,结束日期应该是起始日期 + 90天,和你当前的计算逻辑不符。 - 别名引用规则错误:Oracle不允许在同一层SELECT子句中引用前面定义的别名,你直接使用
"Start date"、"End date"作为函数参数会抛出标识符无效的错误。 - 关键字冲突问题:
USER是Oracle内置关键字,直接作为表名、列名使用会报错,需要用双引号包裹。
正确实现方案
Oracle 12c 及以上版本(推荐)
使用CROSS APPLY为每个用户生成对应的周期序列,避免子查询返回多行的问题:
SELECT "USER", start_date AS "Start date", end_date AS "End date", getfunction("USER", start_date, end_date) AS "Get function" FROM ( SELECT u."USER", u.SUBSCRIBE_DATE + (t.lv - 1) * 91 AS start_date, u.SUBSCRIBE_DATE + t.lv * 91 - 1 AS end_date FROM "User" u CROSS APPLY ( SELECT LEVEL lv FROM DUAL CONNECT BY LEVEL <= CEIL((CURRENT_DATE - u.SUBSCRIBE_DATE)/91) ) t ) -- 如果不需要包含还未结束的周期,可加上下面的过滤条件 -- WHERE end_date <= CURRENT_DATE
Oracle 12c 以下版本兼容写法
如果数据库版本不支持CROSS APPLY,可以先生成全局最大周期序列再关联用户表过滤:
SELECT "USER", start_date AS "Start date", end_date AS "End date", getfunction("USER", start_date, end_date) AS "Get function" FROM ( SELECT u."USER", u.SUBSCRIBE_DATE + (t.lv - 1) * 91 AS start_date, u.SUBSCRIBE_DATE + t.lv * 91 - 1 AS end_date FROM "User" u, ( SELECT LEVEL lv FROM DUAL CONNECT BY LEVEL <= ( SELECT CEIL((CURRENT_DATE - MIN(SUBSCRIBE_DATE))/91) FROM "User" ) ) t WHERE t.lv <= CEIL((CURRENT_DATE - u.SUBSCRIBE_DATE)/91) ) -- 可选过滤未结束的周期 -- WHERE end_date <= CURRENT_DATE
内容的提问来源于stack exchange,提问作者b.delbrouck
相关产品推荐
相关产品推荐

