PL/SQL统计用户计数遇类型错误,请求排查解决
搞定你的PL/SQL编译错误&统计需求
嘿,我来帮你搞定这个编译错误,顺便优化下你的统计逻辑。首先看你报的PLS-00382错误,核心问题是提取日期的日/月部分时用错了语法,直接写dd1 :=(test_date1,'dd')这种写法PL/SQL根本不认识,导致类型不匹配。下面一步步解决:
1. 先修复日期提取的语法问题
要从DATE变量里抠出日或者月,得用正确的函数,两种常用方法任你选:
- 用
EXTRACT直接提取数值(推荐,更直观):dd1 := EXTRACT(DAY FROM test_date1); - 用
TO_CHAR转成字符串再转数字:dd1 := TO_NUMBER(TO_CHAR(test_date1, 'DD'));
这两种写法都能解决类型不匹配的错误。
2. 优化多余的循环逻辑
你的循环For Years_Ahead In Dd1..Dd2 Loop里,dd1和dd2都是从同一天(2017-12-01)提取的日,范围是1到1,循环只跑一次,完全没必要留着,直接去掉循环执行统计就行,省点性能。
3. 修正查询的时间条件(这个很重要!)
原代码里Where Timestamp Between Test_Date1 And Test_Date1只会统计时间完全等于Test_Date1的记录,这几乎查不到数据吧?应该改成你实际要的范围,比如Test_Date1到Test_Date2(也就是00:00到08:00)。另外New_Var1和New_Var2的查询语句完全重复,这是冗余的,要么合并要么改成你需要的其他统计维度。
修正后的完整代码
set serveroutput on; set define off; exec dbms_output.enable(20000); set pagesize 2000; declare Test_Date1 Date; test_date2 DATE; Day_Of_Week Varchar2(3); Years_Ahead Number := 0; New_Var Number := 0; New_Var1 Number := 0; New_Var2 Number := 0; Dd1 Number := 0; Dd2 Number := 0; Mm1 Number := 0; mm2 Number := 0; Begin test_date1 := TO_DATE('01/12/2017 00:00:00','DD/MM/YYYY HH24:MI:SS'); test_date2 := To_Date('01/12/2017 08:00:00','DD/MM/YYYY HH24:MI:SS'); -- 修复日期提取的语法错误,用EXTRACT直接取日和月 dd1 := EXTRACT(DAY FROM test_date1); dd2 := EXTRACT(DAY FROM test_date2); mm1 := EXTRACT(MONTH FROM test_date1); mm2 := EXTRACT(MONTH FROM Test_Date2); -- 去掉多余循环,直接执行统计 -- 统计00:00到08:00的用户数 Select Count(User_Id) Into New_Var From Lg_Usage_Statistics Where Timestamp Between Test_Date1 And Test_Date2; -- 统计12月1日全天到12月2日23:59:59的用户数(把00改成59更准确) Select Count(User_Id) Into New_Var1 From Lg_Usage_Statistics Where Timestamp Between TO_DATE('01/12/2017 00:00:00','DD/MM/YYYY HH24:MI:SS') And TO_DATE('02/12/2017 23:59:59','DD/MM/YYYY HH24:MI:SS'); -- 如果需要其他统计维度,修改这里的时间条件即可 -- Select COUNT(User_Id) into New_Var2 From Lg_Usage_Statistics Where ...; -- 可以输出结果验证,方便调试 dbms_output.put_line('00:00-08:00的用户数: ' || New_Var); dbms_output.put_line('12/01到12/02全天的用户数: ' || New_Var1); END; /
额外小建议
- 如果
User_Id可能有空值,COUNT(User_Id)会忽略空值,要是想统计所有行数就用COUNT(*); - 时间范围的结束值用
23:59:59比23:59:00更靠谱,不会漏掉最后一分钟的记录; - 要是以后要统计多个日期范围,建议把重复的查询逻辑封装成函数,代码更简洁。
内容的提问来源于stack exchange,提问作者ShinnySoul
相关产品推荐
相关产品推荐

