我有以下SQL查询在Oracle SQL开发人员中正确运行,但是当它通过标准的java spring JDBCTemptate查询执行时,它会失败。
SELECT
REPLACE(:RUN_DATE,'-','/') as rep_day,
9,
'BILLING',
ROUND(x.duration_minutes),
ROUND(x.duration_minutes),
'(' || bc.description || ') ' || x.total_ba || ' Accounts; ' || (case when (x.duration_minutes/60) > 1 then FLOOR(x.duration_minutes/60) ||'h' end) || round(mod(x.duration_minutes,60)) || 'min'
FROM
(SELECT bt.bill_cycle_id,
bt.invoice_period,
bt.invoice_period_end_date,
sum((bt.execution_end - bt.execution_start)*24*60) AS duration_minutes,
sum((
CASE
WHEN bt.task = 'BILL'
THEN bt.number_of_accounts
else 0
end))AS total_ba,
min(trunc(bt.execution_start)) as start_date
FROM billing.billing_tasks bt
WHERE bt.type = 'REAL_BILL_RUN'
AND bt.status = 'COMP'
AND trunc(bt.execution_start) = (SELECT to_date(MAX(START_DATE),'dd-mm-yyyy') FROM BILLING.BILL_RUNS WHERE TYPE='REAL_BILL_RUN')
group by bt.bill_cycle_id,
bt.invoice_period,
bt.invoice_period_end_date
) x
INNER JOIN billing.bill_cycles bc
ON bc.id = x.bill_cycle_id
java代码是
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Override
public List<KpiData> runQuery(String runDate) throws Exception {
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(oracleDataSource);
Map map = new HashMap<>();
map.put(GenerateDailyReport.RUN_DATE, runDate);
List<KpiData> kpis = jdbcTemplate.query(sql, map, new KpiDataRowMapper());
return kpis;
}
我知道问题在于'trunc(bt.execution_start)'子句。原始日期子句是这样的,其中:RUN_DATE是参数
AND trunc(bt.execution_start) = to_date(:RUN_DATE,'dd-mm-yyyy');
但我已更新查询以获取最近的帐单运行日期。
AND trunc(bt.execution_start) = (SELECT to_date(MAX(START_DATE),'dd-mm-yyyy') FROM BILLING.BILL_RUNS WHERE TYPE='REAL_BILL_RUN')
有人发现导致此失败的SQL问题吗?
答案 0 :(得分:0)
在子选择中而不是使用&#39; to_date&#39;
AND trunc(bt.execution_start) = (SELECT to_date(MAX(START_DATE),'dd-mm-yyyy') FROM BILLING.BILL_RUNS WHERE TYPE='REAL_BILL_RUN')
我刚才打电话给&#39; trunc()&#39;将现有日期类型字段START_DATE转换为与左侧操作符相同的格式&#39; trunc(bt.execution_start)&#39;。
答案 1 :(得分:0)
我很高兴您找到了解决问题的方法。
有趣的是,你的回答提供了关于你的原始查询无效的原因的缺失线索,我认为解释它是非常有用的。
原帖中不清楚的是start_date
已经是date
字段。既然如此,在to_date()
字段上调用date
是没有意义的。 to_date()
只应用于将字符串转换为日期,而不是日期转换为日期。
事实上,尝试在日期值上调用to_date
通常会导致非常不直观的结果,这就是您所经历的。
让我们假装max(start_date)
是Sept 21st, 2015
的一秒钟。不管你信不信,做to_date(max(start_date), 'dd-mm-yyyy')
会给你Sept 21st, 0015
(不是2015
)。尝试此查询以确认奇怪的行为:
select to_char(to_date(max(start_date), 'dd-mm-yyyy'), 'YYYY-MM-DD')
from BILLING.BILL_RUNS
where TYPE='REAL_BILL_RUN'
你到了什么日期?不是你的期望?
之所以发生这种情况,是因为to_date()
需要一个字符串参数。因此,当您传递日期时,它需要在调用to_date()
函数之前使用默认日期格式将您的日期隐式转换为字符串。换句话说:
to_date(max(start_date), 'dd-mm-yyyy')
......真的变成了这个:
to_date(to_char(max(start_date)), 'dd-mm-yyyy') -- notice the to_char()
如果是Sept 21, 2015
之类的日期,则to_char()
函数可能会返回21-SEP-15
之类的内容(注意2位数年份)。
所以,从逻辑上讲,尝试解析一个2位数年份的字符串,同时指定4位数的年份格式,如下所示:
to_date('21-SEP-15', 'dd-mm-yyyy')
...将导致0015
年而不是2015
。不好。
总结: 永远不会将日期参数传递给对to_date()
的调用。