Oracle OVER (PARTITION BY ) 可以过滤吗
Oracle OVER (PARTITION BY) 语句本身并不具有过滤功能,它主要用于在窗口函数中指定分组规则。但是可以通过在 OVER 子句中嵌套 WHERE 子句来实现对结果集的过滤。例如:
SELECT column1, column2, SUM(column3) OVER (PARTITION BY column1)
FROM table1
WHERE column2 = 'value';
在这个例子中,OVER (PARTITION BY column1) 表示对 column1 进行分组求和,而 WHERE 子句则用于过滤 column2 等于 'value' 的行。
Oracle 中的 over
在 Oracle 中,over 是用于窗口函数的关键字,用于指定函数计算的窗口范围。窗口函数是一种特殊类型的 SQL 函数,允许在结果集中的一组行上执行聚合计算,而不是在整个结果集上执行。
over 子句的一般语法如下:
SELECT column1, column2, ..., function(column)
OVER (
[PARTITION BY partition_expression, ... ]
[ORDER BY sort_expression [ASC | DESC], ... ]
[frame_clause]
)
FROM table_name;
其中,partition_expression 用于指定分区,sort_expression 用于指定排序,frame_clause 用于指定窗口帧范围。
over 子句的作用是将窗口函数应用于指定的行集合,而不是整个结果集。这样,可以在结果集中分组、排序和过滤,并计算每个分组、排序和过滤后的子集的聚合值。
oracle执行报错ora-00928,错误位置显示是MERGE INTO,SQL如下:WITH FGT_FILTERED AS ( SELECT FGT10 AS BPM_ID, FGT02, SUBSTR(FGT08, 3, 1) AS STATUS_RAW, TRUNC(FGT02) AS FGT02_TRUNC – 预计算TRUNC结果 FROM FINGER5.FGT_FILE WHERE SUBSTR(FGT08, 3, 1) = ‘1’ AND FGT02 >= TRUNC(SYSDATE, ‘MM’) AND FGT02 < TRUNC(LAST_DAY(SYSDATE)) + 1 ), FGT_LIST AS ( SELECT STATUS_RAW AS STATUS, FGT02, BPM_ID, ROW_NUMBER() OVER ( PARTITION BY BPM_ID, FGT02_TRUNC – 使用预计算字段 ORDER BY FGT02 DESC ) AS RN FROM FGT_FILTERED ) MERGE INTO EMP_CARDING_TEMP T USING ( SELECT BPM_ID, FGT02 FROM FGT_LIST WHERE RN = 1 – 无需GROUP BY ) S ON ( T.CDAY = P_DATE AND T.BPM_ID = S.BPM_ID AND ( (T.SHIFT_NAME LIKE ‘%白班%’ AND T.CDAY = S.FGT02_TRUNC) OR (T.SHIFT_NAME LIKE ‘%晚班%’ AND T.CDAY = S.FGT02_TRUNC) OR (T.SHIFT_NAME LIKE ‘%晚班%’ AND S.FGT02 < T.CDAY + 1 + INTERVAL ‘01:40’ HOUR TO MINUTE) ) ) WHEN MATCHED THEN UPDATE SET T.INACTUAL = S.FGT02;
用户提供的SQL看起来比较复杂,里面有CTE(公共表表达式),然后MERGE INTO部分。首先,我要检查整个SQL的结构是否正确。MERGE INTO语句的正确结构应该是:MERGE INTO table USING (subquery) ON (condition) WHEN MATCHED THEN UPDATE...。用户的结构大致是这样,但可能有语法问题。
先看CTE部分。第一个CTE是FGT_FILTERED,里面有一个注释用了中文的破折号“– 预计算TRUNC结果”,这里可能有问题。因为Oracle的注释应该是两个连字符“--”,而不是中文的破折号。这可能导致语法错误,从而引发ORA-00928,因为后面的部分可能被错误解析,导致MERGE INTO结构不正确。
接下来检查字符串的引号。用户代码中使用了‘%白班%’这样的单引号,看起来用的是中文的引号,这可能也是问题。Oracle要求使用英文的单引号,如果用户不小心用了中文或全角引号,会导致语法错误,进而引发ORA-00928。例如,'%白班%'应该是英文的撇号,而不是中文的‘或’。
然后看MERGE INTO部分。ON子句中的条件可能有问题。用户使用了T.CDAY = P_DATE,这里的P_DATE是不是一个绑定变量?如果P_DATE没有正确声明或赋值,可能也会导致错误。此外,ON子句中的条件是否正确,特别是涉及日期和INTERVAL的部分。例如,S.FGT02 < T.CDAY + 1 + INTERVAL ‘01:40’ HOUR TO MINUTE,这里的INTERVAL语法是否正确?Oracle中的INTERVAL应该写成INTERVAL '01:40' HOUR TO MINUTE,但要注意引号是否正确,以及是否使用了英文符号。
另外,检查MERGE语句的各个部分是否有遗漏。例如,USING子句后的别名是否正确,WHEN MATCHED THEN UPDATE后面是否缺少了WHERE条件,或者UPDATE语句的语法是否正确。比如,用户只写了UPDATE SET T.INACTUAL = S.FGT02,但可能需要指定更多条件,或者检查是否有逗号分隔多个SET子句。
还要注意CTE和MERGE之间的部分是否有正确的分隔。CTE后面应该直接跟MERGE语句,中间不能有其他内容。用户的代码在FGT_LIST的CTE之后直接开始MERGE,这部分结构是对的。
再检查列名和表名是否存在拼写错误,比如EMP_CARDING_TEMP表是否存在,是否有CDAY、BPM_ID等列。如果表或列不存在,也可能导致错误,但ORA-00928更可能出现在语法错误而非对象不存在的情况。
总结可能的错误点:
- CTE中的注释用了中文破折号,应该改为“--”。
- 字符串中的引号用了中文符号,应改为英文单引号。
- INTERVAL语法中的引号是否正确。
- ON子句中的P_DATE变量是否正确声明。
- MERGE语句的结构是否完整,比如是否缺少必要的关键字。
修正这些地方后,再测试SQL是否执行成功。如果用户是在PL/SQL环境中执行,还需要确保绑定变量P_DATE已经正确声明和赋值。根据提供的SQL代码,ORA-00928错误(缺失SELECT关键字)主要集中在以下关键问题上:
一、语法层面分析
1. 中文符号导致语法中断
- 问题代码:
– 预计算TRUNC结果
- 此处的注释符
–
是中文破折号,Oracle只识别标准注释符--
(两个英文短横线)。
- 此处的注释符
- 问题代码:
‘%白班%’
和‘%晚班%’
- 字符串引号使用中文单引号
‘’
,必须改为英文单引号''
。
- 字符串引号使用中文单引号
2. INTERVAL语法错误
- 问题代码:
INTERVAL ‘01:40’ HOUR TO MINUTE
HOUR TO MINUTE
格式需要指定完整的间隔单位,应改为HOUR TO MINUTE
或调整时间格式:INTERVAL '01:40' HOUR TO MINUTE -- 正确
3. MERGE语句结构缺陷
- 缺失
WHEN NOT MATCHED
子句- Oracle要求
MERGE
必须包含至少一个WHEN MATCHED
或WHEN NOT MATCHED
,否则会报错。如果不需要插入新数据,需补充空子句:WHEN NOT MATCHED THEN INSERT (CDAY, BPM_ID, INACTUAL) VALUES (P_DATE, S.BPM_ID, S.FGT02)
- Oracle要求
二、建议修正后的SQL
WITH FGT_FILTERED AS (
SELECT
FGT10 AS BPM_ID,
FGT02,
SUBSTR(FGT08, 3, 1) AS STATUS_RAW,
TRUNC(FGT02) AS FGT02_TRUNC -- 预计算TRUNC结果(修正注释符)
FROM FINGER5.FGT_FILE
WHERE SUBSTR(FGT08, 3, 1) = '1' -- 修正引号
AND FGT02 >= TRUNC(SYSDATE, 'MM')
AND FGT02 < TRUNC(LAST_DAY(SYSDATE)) + 1
),
FGT_LIST AS (
SELECT
STATUS_RAW AS STATUS,
FGT02,
BPM_ID,
ROW_NUMBER() OVER (
PARTITION BY BPM_ID, FGT02_TRUNC -- 使用预计算字段
ORDER BY FGT02 DESC
) AS RN
FROM FGT_FILTERED
)
MERGE INTO EMP_CARDING_TEMP T
USING (
SELECT
BPM_ID,
FGT02,
FGT02_TRUNC -- 需补充此字段供ON条件使用
FROM FGT_LIST
WHERE RN = 1
) S ON (
T.CDAY = P_DATE
AND T.BPM_ID = S.BPM_ID
AND (
(T.SHIFT_NAME LIKE '%白班%' AND T.CDAY = S.FGT02_TRUNC) -- 修正引号
OR (T.SHIFT_NAME LIKE '%晚班%' AND T.CDAY = S.FGT02_TRUNC)
OR (T.SHIFT_NAME LIKE '%晚班%' AND S.FGT02 < T.CDAY + 1 + INTERVAL '01:40' HOUR TO MINUTE)
)
)
WHEN MATCHED THEN
UPDATE SET T.INACTUAL = S.FGT02
WHEN NOT MATCHED THEN -- 补充缺失的子句
INSERT (CDAY, BPM_ID, INACTUAL)
VALUES (P_DATE, S.BPM_ID, S.FGT02);
三、其他潜在问题
变量
P_DATE
未定义- 确保
P_DATE
是绑定变量或在上下文中已声明(如PL/SQL块中定义)。
- 确保
字段
FGT02_TRUNC
未在USING子句中选择- 原USING子句未包含
FGT02_TRUNC
,但ON条件中引用了该字段,需在子查询中显式选择。
- 原USING子句未包含
性能优化建议
- 考虑在
FGT_FILE
表上为FGT08
、FGT02
等字段建立索引,加速SUBSTR
和日期过滤。
- 考虑在
四、验证步骤
单独执行CTE
先运行WITH FGT_FILTERED AS (...)
部分,确认子查询能正常返回数据。分段调试MERGE
将USING
子查询单独执行,检查结果是否符合预期(如RN=1
是否筛选到正确记录)。检查绑定变量
确保P_DATE
的值已正确传递(尤其在PL/SQL环境中)。
相关推荐
















