转载with as、case when、merge into、分析函数over()

本文介绍了 Oracle SQL 中的高级特性,包括 WITH AS 子句的使用方法及其优化效果、CASE WHEN 语句的不同形式及应用场景、MERGE INTO 语句在 Oracle 11g 中的特性以及分析函数 OVER 的具体运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1) with as

a) WITH AS短语,也叫做子查询部分(subquery factoring),可以定义一个SQL片断,该SQL片断会被整个SQL语句所用到。

b) 当查询中多次用到某一部分时,可以用Oracle with语句创建一个公共临时表。因为子查询在内存临时表中,避免了重复解析,所以执行效率会提高不少。临时表在一次查询结束自动清除。

c) 应用:需多次调用;union all中;

d) 示例

with
    sql1 as (select s_name from test_tempa),
    sql2 as (select s_name from test_tempb where not exists (select s_name from sql1))
    select * from sql1
    union all
    select * from sql2
    union all
    select 'no records' from dual
      where not exists (select s_name from sql1 where)
               and not exists (select s_name from sql2);

2) case when

a) 简单case语句

select case to_char(sysdate,’d’) 
    when1then ‘周日’
    when2then ‘周一’ 
    else ‘不知道’
    end 
    from dual;

b) 搜索case语句

SELECT   count(col3), sum(CASE WHEN col3 = 1 THEN 1   
                       ELSE 0
                       END) ,
                sum(CASE WHEN col3 = 2 THEN 1
                       ELSE 0
                       END) 
    FROM table_name;

c) where case when 用法

    SELECT T2.*, T1.*
       FROM T1, T2
      WHERE (CASE WHEN T2.col2 = 'A' AND
                   T1.col3 = 'B'
                THEN 1
              WHEN T2.col2 != 'A' AND
                   T1.col3 != 'B'
                THEN 1
              ELSE 0
           END) = 1

d) group by case when 用法

SELECT  CASE 
    WHEN col2 = '05' THEN '1'  
    WHEN col2 = '23'  THEN '2'  
    ELSE NULL END "类别",
    COUNT(*)  
    FROM  table_name
    GROUP BY  CASE 
    WHEN col2 = '05' THEN '1'  
    WHEN col2 = '23'  THEN '2'  
    ELSE NULL END;

3) merge into

在oracle 11g中有如下特点
a) update和insert子句时可选的。

b) update和insert子句可以加where子句

merge into table_a a
using table_b b
on (a.id = b.id)
when matched then
        update set a.name = b.name where ……
when not matched then
        insert values (a.id,a.name) where ……

4) 分析函数over()

a) ROW_NUMBER(),不允许并列名次、相同值名次不重复,结果如123456……

b) RANK(),跳跃排序,允许并列名次、复制名次自动空缺,结果如12245558……

c) DENSE_RANK(),允许并列名次、名次不间断,结果如122344456……

d) 例子:

select * from (
        selelct row_number() over(partition by xxx2 order by xxx3 ) rw from dual)tt where tt.rw = ?;
declare v_1 date := TO_DATE('20250301', 'YYYYMMDD'); v_start date; v_end date := trunc(sysdate); v_current date; v_sql varchar2(5000); begin v_start :=trunc(v_1); for i in 0..(v_end-v_start) loop v_current := v_start+i; v_sql := 'insert into PURE_REPAYMENT_AMOUNT with t1 as (SELECT a.*,CASE WHEN a.COUNTRY_CODE = ''tz'' THEN a.IN_FORCE_DATE + 3 / 24 WHEN a.COUNTRY_CODE = ''ke'' THEN a.IN_FORCE_DATE + 3 / 24 WHEN a.COUNTRY_CODE = ''ci'' THEN a.IN_FORCE_DATE WHEN a.COUNTRY_CODE = ''ph'' THEN a.IN_FORCE_DATE + 8 / 24 END AS NEW_DATE FROM LOAN_BORROW_INFO_TEST a WHERE a.COUNTRY_CODE <> ''gh'' AND a.RISK_SERIAL_NO <> ''googleplay'' AND a.ARCHIVED=1 and a.IN_FORCE_DATE is not null), t2 as (select distinct phone,country_code,NEW_DATE from t1 where TRUNC(NEW_DATE)=TO_DATE(''' || TO_CHAR(v_current, 'YYYYMMDD') || ''', ''YYYYMMDD'')and user_type_product=0), t3 as ( select t1.NEW_DATE,t1.REPAYMENT_AMOUNT from t2 left join t1 on t2.phone=t1.phone and t2.country_code=t1.country_code and t1.NEW_DATE>=t2.NEW_DATE and t1.new_date is not null), t4 as( select week_num,TO_DATE(''' || TO_CHAR(v_current, 'YYYYMMDD') || ''', ''YYYYMMDD'') as pure_in_force_date,SUM(REPAYMENT_AMOUNT/100) AS total_AMOUNT from (SELECT REPAYMENT_AMOUNT, TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7)+1 AS week_num, MIN(NEW_DATE) OVER () + TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7) * 7 AS week_start, MIN(NEW_DATE) OVER () + TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7) * 7 + 6 AS week_end FROM t3 WHERE NEW_DATE BETWEEN TO_DATE(''2025-03-01'', ''YYYY-MM-DD'') AND TRUNC(ADD_MONTHS(SYSDATE, 12), "YYYY") - 1) GROUP BY week_num ORDER BY week_num), t5 as(select * from t4 pivot(sum(total_AMOUNT) for week_num IN (1 AS "第一周", 2 AS "第二周", 3 AS "第三周", 4 AS "第四周", 5 AS "第五周", 6 AS "第六周", 7 AS "第七周", 8 AS "第八周", 9 AS "第九周", 10 AS "第十周", 11 AS "第十一周", 12 AS "第十二周", 13 AS "第十三周", 14 AS "第十四周", 15 AS "第十五周", 16 AS "第十六周", 17 AS "第十七周", 18 AS "第十八周", 19 AS "第十九周", 20 AS "第二十周", 21 AS "第二十一周", 22 AS "第二十二周", 23 AS "第二十三周", 24 AS "第二十四周", 25 AS "第二十五周", 26 AS "第二十六周", 27 AS "第二十七周", 28 AS "第二十八周", 29 AS "第二十九周", 30 AS "第三十周", 31 AS "第三十一周", 32 AS "第三十二周", 33 AS "第三十三周", 34 AS "第三十四周", 35 AS "第三十五周", 36 AS "第三十六周", 37 AS "第三十七周", 38 AS "第三十八周", 39 AS "第三十九周", 40 AS "第四十周", 41 AS "第四十一周", 42 AS "第四十二周", 43 AS "第四十三周"))) select t5.* from t5'; EXECUTE IMMEDIATE v_sql; END LOOP; end;改成mergeinto的语句
06-07
declare v_1 date := TO_DATE('20250301', 'YYYYMMDD'); v_start date; v_end date := trunc(sysdate); v_current date; v_sql varchar2(32767); begin v_start :=trunc(v_1); for i in 0..(v_end-v_start) loop v_current := v_start+i; v_sql := 'merge into PURE_SPREAD dest using (with t1 as (SELECT a.*,CASE WHEN a.COUNTRY_CODE = ''tz'' THEN a.IN_FORCE_DATE + 3 / 24 WHEN a.COUNTRY_CODE = ''ke'' THEN a.IN_FORCE_DATE + 3 / 24 WHEN a.COUNTRY_CODE = ''ci'' THEN a.IN_FORCE_DATE WHEN a.COUNTRY_CODE = ''ph'' THEN a.IN_FORCE_DATE + 8 / 24 END AS NEW_DATE FROM LOAN_BORROW_INFO_TEST a WHERE a.COUNTRY_CODE <> ''gh'' AND a.RISK_SERIAL_NO <> ''googleplay'' AND a.ARCHIVED=1 and a.IN_FORCE_DATE is not null), t2 as (select distinct phone,country_code,NEW_DATE from t1 where TRUNC(NEW_DATE)=TO_DATE(''' || TO_CHAR(v_current, 'YYYYMMDD') || ''', ''YYYYMMDD'') and user_type_product=0), t3 as ( select t1.NEW_DATE,t1.ACTUAL_REPAYMENT_AMOUNT,t1.ACTUAL_AMOUNT,t1.state from t2 left join t1 on t2.phone=t1.phone and t2.country_code=t1.country_code and t1.NEW_DATE>=t2.NEW_DATE and t1.new_date is not null), t4 as( select week_num,TO_DATE(''' || TO_CHAR(v_current, 'YYYYMMDD') || ''', ''YYYYMMDD'') as pure_in_force_date,sum(rs-rl)/100 AS Spread from (SELECT case when state !=6 then ACTUAL_REPAYMENT_AMOUNT-ACTUAL_AMOUNT else 0 end as rs, case when state = 6 then ACTUAL_AMOUNT else 0 end as rl, TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7)+1 AS week_num, MIN(NEW_DATE) OVER () + TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7) * 7 AS week_start, MIN(NEW_DATE) OVER () + TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7) * 7 + 6 AS week_end FROM t3 WHERE NEW_DATE BETWEEN TO_DATE("2025-03-01", "YYYY-MM-DD") AND TRUNC(ADD_MONTHS(SYSDATE, 12), "YYYY") - 1) GROUP BY week_num ORDER BY week_num) select * from t4 pivot(sum(round(Spread,6)) for week_num IN (1 AS "第一周", 2 AS "第二周", 3 AS "第三周", 4 AS "第四周", 5 AS "第五周", 6 AS "第六周", 7 AS "第七周", 8 AS "第八周", 9 AS "第九周", 10 AS "第十周", 11 AS "第十一周", 12 AS "第十二周", 13 AS "第十三周", 14 AS "第十四周", 15 AS "第十五周", 16 AS "第十六周", 17 AS "第十七周", 18 AS "第十八周", 19 AS "第十九周", 20 AS "第二十周", 21 AS "第二十一周", 22 AS "第二十二周", 23 AS "第二十三周", 24 AS "第二十四周", 25 AS "第二十五周", 26 AS "第二十六周", 27 AS "第二十七周", 28 AS "第二十八周", 29 AS "第二十九周", 30 AS "第三十周", 31 AS "第三十一周", 32 AS "第三十二周", 33 AS "第三十三周", 34 AS "第三十四周", 35 AS "第三十五周", 36 AS "第三十六周", 37 AS "第三十七周", 38 AS "第三十八周", 39 AS "第三十九周", 40 AS "第四十周", 41 AS "第四十一周", 42 AS "第四十二周", 43 AS "第四十三周"))) src on ( dest.pure_in_force_date= src.pure_in_force_date ) WHEN MATCHED THEN UPDATE SET dest."第一周" = src."第一周",dest."第二周" = src."第二周",dest."第三周" = src."第三周",dest."第四周" = src."第四周",dest."第五周" = src."第五周",dest."第六周" = src."第六周",dest."第七周" = src."第七周",dest."第八周" = src."第八周",dest."第九周" = src."第九周",dest."第十周" = src."第十周",dest."第十一周" = src."第十一周",dest."第十二周" = src."第十二周",dest."第十三周" = src."第十三周",dest."第十四周" = src."第十四周",dest."第十五周" = src."第十五周",dest."第十六周" = src."第十六周",dest."第十七周" = src."第十七周",dest."第十八周" = src."第十八周",dest."第十九周" = src."第十九周",dest."第二十周" = src."第二十周",dest."第二十一周" = src."第二十一周",dest."第二十二周" = src."第二十二周",dest."第二十三周" = src."第二十三周",dest."第二十四周" = src."第二十四周",dest."第二十五周" = src."第二十五周",dest."第二十六周" = src."第二十六周",dest."第二十七周" = src."第二十七周",dest."第二十八周" = src."第二十八周",dest."第二十九周" = src."第二十九周",dest."第三十周" = src."第三十周",dest."第三十一周" = src."第三十一周",dest."第三十二周" = src."第三十二周",dest."第三十三周" = src."第三十三周",dest."第三十四周" = src."第三十四周",dest."第三十五周" = src."第三十五周",dest."第三十六周" = src."第三十六周",dest."第三十七周" = src."第三十七周",dest."第三十八周" = src."第三十八周",dest."第三十九周" = src."第三十九周",dest."第四十周" = src."第四十周",dest."第四十一周" = src."第四十一周",dest."第四十二周" = src."第四十二周",dest."第四十三周" = src."第四十三周" WHEN NOT MATCHED THEN INSERT ( pure_in_force_date, "第一周","第二周","第三周","第四周","第五周","第六周","第七周","第八周","第九周","第十周","第十一周","第十二周","第十三周","第十四周","第十五周","第十六周","第十七周","第十八周","第十九周","第二十周","第二十一周","第二十二周","第二十三周","第二十四周","第二十五周","第二十六周","第二十七周","第二十八周","第二十九周","第三十周","第三十一周","第三十二周","第三十三周","第三十四周","第三十五周","第三十六周","第三十七周","第三十八周","第三十九周","第四十周","第四十一周","第四十二周","第四十三周" ) VALUES ( src.pure_in_force_date, src."第一周",src."第二周",src."第三周",src."第四周",src."第五周",src."第六周",src."第七周",src."第八周",src."第九周",src."第十周",src."第十一周",src."第十二周",src."第十三周",src."第十四周",src."第十五周",src."第十六周",src."第十七周",src."第十八周",src."第十九周",src."第二十周",src."第二十一周",src."第二十二周",src."第二十三周",src."第二十四周",src."第二十五周",src."第二十六周",src."第二十七周",src."第二十八周",src."第二十九周",src."第三十周",src."第三十一周",src."第三十二周",src."第三十三周",src."第三十四周",src."第三十五周",src."第三十六周",src."第三十七周",src."第三十八周",src."第三十九周",src."第四十周",src."第四十一周",src."第四十二周",src."第四十三周" )' ; EXECUTE IMMEDIATE v_sql; END LOOP; end; declare v_1 date := TO_DATE('20250301', 'YYYYMMDD'); v_start date; v_end date := trunc(sysdate); v_current date; v_sql varchar2(32767); begin v_start :=trunc(v_1); for i in 0..(v_end-v_start) loop v_current := v_start+i; v_sql := 'merge into PURE_SPREAD dest using (with t1 as (SELECT a.*,CASE WHEN a.COUNTRY_CODE = ''tz'' THEN a.IN_FORCE_DATE + 3 / 24 WHEN a.COUNTRY_CODE = ''ke'' THEN a.IN_FORCE_DATE + 3 / 24 WHEN a.COUNTRY_CODE = ''ci'' THEN a.IN_FORCE_DATE WHEN a.COUNTRY_CODE = ''ph'' THEN a.IN_FORCE_DATE + 8 / 24 END AS NEW_DATE FROM LOAN_BORROW_INFO_TEST a WHERE a.COUNTRY_CODE <> ''gh'' AND a.RISK_SERIAL_NO <> ''googleplay'' AND a.ARCHIVED=1 and a.IN_FORCE_DATE is not null), t2 as (select distinct phone,country_code,NEW_DATE from t1 where TRUNC(NEW_DATE)=TO_DATE(''' || TO_CHAR(v_current, 'YYYYMMDD') || ''', ''YYYYMMDD'') and user_type_product=0), t3 as ( select t1.NEW_DATE,t1.ACTUAL_REPAYMENT_AMOUNT,t1.ACTUAL_AMOUNT,t1.state from t2 left join t1 on t2.phone=t1.phone and t2.country_code=t1.country_code and t1.NEW_DATE>=t2.NEW_DATE and t1.new_date is not null), t4 as( select week_num,TO_DATE(''' || TO_CHAR(v_current, 'YYYYMMDD') || ''', ''YYYYMMDD'') as pure_in_force_date,sum(rs-rl)/100 AS Spread from (SELECT case when state !=6 then ACTUAL_REPAYMENT_AMOUNT-ACTUAL_AMOUNT else 0 end as rs, case when state = 6 then ACTUAL_AMOUNT else 0 end as rl, TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7)+1 AS week_num, MIN(NEW_DATE) OVER () + TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7) * 7 AS week_start, MIN(NEW_DATE) OVER () + TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7) * 7 + 6 AS week_end FROM t3 WHERE NEW_DATE BETWEEN TO_DATE("2025-03-01", "YYYY-MM-DD") AND TRUNC(ADD_MONTHS(SYSDATE, 12), "YYYY") - 1) GROUP BY week_num ORDER BY week_num) select * from t4 pivot(sum(round(Spread,6)) for week_num IN (1 AS "第一周", 2 AS "第二周", 3 AS "第三周", 4 AS "第四周", 5 AS "第五周", 6 AS "第六周", 7 AS "第七周", 8 AS "第八周", 9 AS "第九周", 10 AS "第十周", 11 AS "第十一周", 12 AS "第十二周", 13 AS "第十三周", 14 AS "第十四周", 15 AS "第十五周", 16 AS "第十六周", 17 AS "第十七周", 18 AS "第十八周", 19 AS "第十九周", 20 AS "第二十周", 21 AS "第二十一周", 22 AS "第二十二周", 23 AS "第二十三周", 24 AS "第二十四周", 25 AS "第二十五周", 26 AS "第二十六周", 27 AS "第二十七周", 28 AS "第二十八周", 29 AS "第二十九周", 30 AS "第三十周", 31 AS "第三十一周", 32 AS "第三十二周", 33 AS "第三十三周", 34 AS "第三十四周", 35 AS "第三十五周", 36 AS "第三十六周", 37 AS "第三十七周", 38 AS "第三十八周", 39 AS "第三十九周", 40 AS "第四十周", 41 AS "第四十一周", 42 AS "第四十二周", 43 AS "第四十三周"))) src on ( dest.pure_in_force_date= src.pure_in_force_date ) WHEN MATCHED THEN UPDATE SET dest."第一周" = src."第一周",dest."第二周" = src."第二周",dest."第三周" = src."第三周",dest."第四周" = src."第四周",dest."第五周" = src."第五周",dest."第六周" = src."第六周",dest."第七周" = src."第七周",dest."第八周" = src."第八周",dest."第九周" = src."第九周",dest."第十周" = src."第十周",dest."第十一周" = src."第十一周",dest."第十二周" = src."第十二周",dest."第十三周" = src."第十三周",dest."第十四周" = src."第十四周",dest."第十五周" = src."第十五周",dest."第十六周" = src."第十六周",dest."第十七周" = src."第十七周",dest."第十八周" = src."第十八周",dest."第十九周" = src."第十九周",dest."第二十周" = src."第二十周",dest."第二十一周" = src."第二十一周",dest."第二十二周" = src."第二十二周",dest."第二十三周" = src."第二十三周",dest."第二十四周" = src."第二十四周",dest."第二十五周" = src."第二十五周",dest."第二十六周" = src."第二十六周",dest."第二十七周" = src."第二十七周",dest."第二十八周" = src."第二十八周",dest."第二十九周" = src."第二十九周",dest."第三十周" = src."第三十周",dest."第三十一周" = src."第三十一周",dest."第三十二周" = src."第三十二周",dest."第三十三周" = src."第三十三周",dest."第三十四周" = src."第三十四周",dest."第三十五周" = src."第三十五周",dest."第三十六周" = src."第三十六周",dest."第三十七周" = src."第三十七周",dest."第三十八周" = src."第三十八周",dest."第三十九周" = src."第三十九周",dest."第四十周" = src."第四十周",dest."第四十一周" = src."第四十一周",dest."第四十二周" = src."第四十二周",dest."第四十三周" = src."第四十三周" WHEN NOT MATCHED THEN INSERT ( pure_in_force_date, "第一周","第二周","第三周","第四周","第五周","第六周","第七周","第八周","第九周","第十周","第十一周","第十二周","第十三周","第十四周","第十五周","第十六周","第十七周","第十八周","第十九周","第二十周","第二十一周","第二十二周","第二十三周","第二十四周","第二十五周","第二十六周","第二十七周","第二十八周","第二十九周","第三十周","第三十一周","第三十二周","第三十三周","第三十四周","第三十五周","第三十六周","第三十七周","第三十八周","第三十九周","第四十周","第四十一周","第四十二周","第四十三周" ) VALUES ( src.pure_in_force_date, src."第一周",src."第二周",src."第三周",src."第四周",src."第五周",src."第六周",src."第七周",src."第八周",src."第九周",src."第十周",src."第十一周",src."第十二周",src."第十三周",src."第十四周",src."第十五周",src."第十六周",src."第十七周",src."第十八周",src."第十九周",src."第二十周",src."第二十一周",src."第二十二周",src."第二十三周",src."第二十四周",src."第二十五周",src."第二十六周",src."第二十七周",src."第二十八周",src."第二十九周",src."第三十周",src."第三十一周",src."第三十二周",src."第三十三周",src."第三十四周",src."第三十五周",src."第三十六周",src."第三十七周",src."第三十八周",src."第三十九周",src."第四十周",src."第四十一周",src."第四十二周",src."第四十三周" )' ; EXECUTE IMMEDIATE v_sql; END LOOP; end; declare v_1 date := TO_DATE('20250301', 'YYYYMMDD'); v_start date; v_end date := trunc(sysdate); v_current date; v_sql varchar2(32767); begin v_start :=trunc(v_1); for i in 0..(v_end-v_start) loop v_current := v_start+i; v_sql := 'merge into PURE_SPREAD dest using (with t1 as (SELECT a.*,CASE WHEN a.COUNTRY_CODE = ''tz'' THEN a.IN_FORCE_DATE + 3 / 24 WHEN a.COUNTRY_CODE = ''ke'' THEN a.IN_FORCE_DATE + 3 / 24 WHEN a.COUNTRY_CODE = ''ci'' THEN a.IN_FORCE_DATE WHEN a.COUNTRY_CODE = ''ph'' THEN a.IN_FORCE_DATE + 8 / 24 END AS NEW_DATE FROM LOAN_BORROW_INFO_TEST a WHERE a.COUNTRY_CODE <> ''gh'' AND a.RISK_SERIAL_NO <> ''googleplay'' AND a.ARCHIVED=1 and a.IN_FORCE_DATE is not null), t2 as (select distinct phone,country_code,NEW_DATE from t1 where TRUNC(NEW_DATE)=TO_DATE(''' || TO_CHAR(v_current, 'YYYYMMDD') || ''', ''YYYYMMDD'') and user_type_product=0), t3 as ( select t1.NEW_DATE,t1.ACTUAL_REPAYMENT_AMOUNT,t1.ACTUAL_AMOUNT,t1.state from t2 left join t1 on t2.phone=t1.phone and t2.country_code=t1.country_code and t1.NEW_DATE>=t2.NEW_DATE and t1.new_date is not null), t4 as( select week_num,TO_DATE(''' || TO_CHAR(v_current, 'YYYYMMDD') || ''', ''YYYYMMDD'') as pure_in_force_date,sum(rs-rl)/100 AS Spread from (SELECT case when state !=6 then ACTUAL_REPAYMENT_AMOUNT-ACTUAL_AMOUNT else 0 end as rs, case when state = 6 then ACTUAL_AMOUNT else 0 end as rl, TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7)+1 AS week_num, MIN(NEW_DATE) OVER () + TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7) * 7 AS week_start, MIN(NEW_DATE) OVER () + TRUNC((NEW_DATE - MIN(NEW_DATE) OVER ()) / 7) * 7 + 6 AS week_end FROM t3 WHERE NEW_DATE BETWEEN TO_DATE("2025-03-01", "YYYY-MM-DD") AND TRUNC(ADD_MONTHS(SYSDATE, 12), "YYYY") - 1) GROUP BY week_num ORDER BY week_num) select * from t4 pivot(sum(round(Spread,6)) for week_num IN (1 AS "第一周", 2 AS "第二周", 3 AS "第三周", 4 AS "第四周", 5 AS "第五周", 6 AS "第六周", 7 AS "第七周", 8 AS "第八周", 9 AS "第九周", 10 AS "第十周", 11 AS "第十一周", 12 AS "第十二周", 13 AS "第十三周", 14 AS "第十四周", 15 AS "第十五周", 16 AS "第十六周", 17 AS "第十七周", 18 AS "第十八周", 19 AS "第十九周", 20 AS "第二十周", 21 AS "第二十一周", 22 AS "第二十二周", 23 AS "第二十三周", 24 AS "第二十四周", 25 AS "第二十五周", 26 AS "第二十六周", 27 AS "第二十七周", 28 AS "第二十八周", 29 AS "第二十九周", 30 AS "第三十周", 31 AS "第三十一周", 32 AS "第三十二周", 33 AS "第三十三周", 34 AS "第三十四周", 35 AS "第三十五周", 36 AS "第三十六周", 37 AS "第三十七周", 38 AS "第三十八周", 39 AS "第三十九周", 40 AS "第四十周", 41 AS "第四十一周", 42 AS "第四十二周", 43 AS "第四十三周"))) src on ( dest.pure_in_force_date= src.pure_in_force_date ) WHEN MATCHED THEN UPDATE SET dest."第一周" = src."第一周",dest."第二周" = src."第二周",dest."第三周" = src."第三周",dest."第四周" = src."第四周",dest."第五周" = src."第五周",dest."第六周" = src."第六周",dest."第七周" = src."第七周",dest."第八周" = src."第八周",dest."第九周" = src."第九周",dest."第十周" = src."第十周",dest."第十一周" = src."第十一周",dest."第十二周" = src."第十二周",dest."第十三周" = src."第十三周",dest."第十四周" = src."第十四周",dest."第十五周" = src."第十五周",dest."第十六周" = src."第十六周",dest."第十七周" = src."第十七周",dest."第十八周" = src."第十八周",dest."第十九周" = src."第十九周",dest."第二十周" = src."第二十周",dest."第二十一周" = src."第二十一周",dest."第二十二周" = src."第二十二周",dest."第二十三周" = src."第二十三周",dest."第二十四周" = src."第二十四周",dest."第二十五周" = src."第二十五周",dest."第二十六周" = src."第二十六周",dest."第二十七周" = src."第二十七周",dest."第二十八周" = src."第二十八周",dest."第二十九周" = src."第二十九周",dest."第三十周" = src."第三十周",dest."第三十一周" = src."第三十一周",dest."第三十二周" = src."第三十二周",dest."第三十三周" = src."第三十三周",dest."第三十四周" = src."第三十四周",dest."第三十五周" = src."第三十五周",dest."第三十六周" = src."第三十六周",dest."第三十七周" = src."第三十七周",dest."第三十八周" = src."第三十八周",dest."第三十九周" = src."第三十九周",dest."第四十周" = src."第四十周",dest."第四十一周" = src."第四十一周",dest."第四十二周" = src."第四十二周",dest."第四十三周" = src."第四十三周" WHEN NOT MATCHED THEN INSERT ( pure_in_force_date, "第一周","第二周","第三周","第四周","第五周","第六周","第七周","第八周","第九周","第十周","第十一周","第十二周","第十三周","第十四周","第十五周","第十六周","第十七周","第十八周","第十九周","第二十周","第二十一周","第二十二周","第二十三周","第二十四周","第二十五周","第二十六周","第二十七周","第二十八周","第二十九周","第三十周","第三十一周","第三十二周","第三十三周","第三十四周","第三十五周","第三十六周","第三十七周","第三十八周","第三十九周","第四十周","第四十一周","第四十二周","第四十三周" ) VALUES ( src.pure_in_force_date, src."第一周",src."第二周",src."第三周",src."第四周",src."第五周",src."第六周",src."第七周",src."第八周",src."第九周",src."第十周",src."第十一周",src."第十二周",src."第十三周",src."第十四周",src."第十五周",src."第十六周",src."第十七周",src."第十八周",src."第十九周",src."第二十周",src."第二十一周",src."第二十二周",src."第二十三周",src."第二十四周",src."第二十五周",src."第二十六周",src."第二十七周",src."第二十八周",src."第二十九周",src."第三十周",src."第三十一周",src."第三十二周",src."第三十三周",src."第三十四周",src."第三十五周",src."第三十六周",src."第三十七周",src."第三十八周",src."第三十九周",src."第四十周",src."第四十一周",src."第四十二周",src."第四十三周" )' ; EXECUTE IMMEDIATE v_sql; END LOOP; end; [42000][904] ORA-00904: "YYYY": 标识符无效 ORA-06512: 在 line 67
06-07
逐句解释SQL -- ================================================================================================= -- SQL SCRIPT FOR DAILY OUTPUT PLAN PROCESSING -- Description: This script refactors the business logic from '日产出目标.py' into a single, -- comprehensive SQL query. It processes work orders, corrects schedule times based on -- resource constraints, and calculates the daily output plan for the next 7 days. -- Target Table: daily_output_plan_final -- ================================================================================================= -- Step 0.1: Create the final output table if it doesn't exist CREATE TABLE IF NOT EXISTS daily_output_plan_final ( "批次" TEXT NOT NULL, "指令" TEXT, "线体" TEXT, "单板代码" TEXT, "单板名称" TEXT, "计划数量" REAL, "产出数量" REAL, "剩余数量" REAL, "计划开始时间" TEXT, "计划结束时间" TEXT, "实际开始时间" TEXT, "修正后计划开始时间" TEXT, "修正后计划结束时间" TEXT, "主工序" TEXT, "工序序号" INTEGER, "入库工序" TEXT, "入库时间" TEXT, "产品大类" TEXT, "工厂" TEXT, "责任人" TEXT, "day_1_output" REAL, "day_2_output" REAL, "day_3_output" REAL, "day_4_output" REAL, "day_5_output" REAL, "day_6_output" REAL, "day_7_output" REAL ); -- Step 0.2: Clean up the final table before insertion DELETE FROM daily_output_plan_final; -- Step 1: Use a CTE to prepare and pre-calculate data, similar to the initial Python DataFrame setup. WITH PreparedData AS ( SELECT wo.prodplanId AS "批次", wo.workOrderNo AS "指令", wo.lineName AS "线体", wo.itemNo AS "单板代码", wo.itemName AS "单板名称", CAST(wo.taskQty AS REAL) AS "计划数量", wo.scheduleStartDate AS "计划开始时间", wo.scheduleEndDate AS "计划结束时间", wo.actualStartDate AS "实际开始时间", wo.craftSection AS "主工序", wo.order_index AS "顺序号", CAST(wo.remark AS INTEGER) AS "工序序号", CAST(wo.outputQty AS REAL) AS "产出数量", wo.externalType AS "产品大类", wo.factoryName AS "工厂", -- Calculate remaining quantity, ensuring it's not negative MAX(0, CAST(wo.taskQty AS REAL) - CAST(wo.outputQty AS REAL)) AS "剩余数量", -- Merge craft data with defaults for calculation COALESCE(cd.unitPerHour, 60) AS "UPH", COALESCE(cd.operationEfficiency, 1) AS "作业效率", COALESCE(cd.transferTime, 0.5) AS "转机时间", COALESCE(cd.endingTime, 0.5) AS "收尾时间", -- Calculate production time in hours (MAX(0, CAST(wo.taskQty AS REAL) - CAST(wo.outputQty AS REAL)) / NULLIF(COALESCE(cd.unitPerHour, 60) * COALESCE(cd.operationEfficiency, 1), 0)) AS production_time, -- Determine if it's the last operation in the batch to mark for warehousing CASE WHEN wo.remark = MAX(wo.remark) OVER (PARTITION BY wo.prodplanId) THEN '是' ELSE '否' END AS "入库工序" FROM work_orders wo LEFT JOIN craft_data cd ON wo.itemNo = cd.itemNo AND wo.craftSection = cd.mainProcess WHERE -- Filter out completed or near-completed orders (CAST(wo.taskQty AS REAL) > 0 AND (CAST(wo.outputQty AS REAL) / CAST(wo.taskQty AS REAL)) <= 0.9) ), -- Step 2: Rank operations to establish a processing order for the recursive CTE RankedData AS ( SELECT *, -- Rank within the same batch ROW_NUMBER() OVER (PARTITION BY "批次" ORDER BY "工序序号") AS op_rank_in_batch, -- Global rank across all data for sequential processing ROW_NUMBER() OVER (ORDER BY "线体", "批次", "工序序号") AS global_rank, -- Pre-calculate total hours for this operation ("转机时间" + production_time + "收尾时间") AS total_hours FROM PreparedData ), -- Step 3: Recursive CTE to correct schedule times, simulating the Python loop CorrectedSchedule AS ( -- Anchor Member: Start with the first operation (global_rank = 1) SELECT rd.global_rank, rd."批次", rd."线体", rd."单板代码", rd."主工序", rd.op_rank_in_batch, rd.total_hours, -- Determine the initial start time COALESCE(rd."实际开始时间", rd."计划开始时间", STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'localtime')) AS corrected_start_time, -- Calculate the initial end time STRFTIME('%Y-%m-%d %H:%M:%S', COALESCE(rd."实际开始时间", rd."计划开始时间", STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'localtime')), '+' || rd.total_hours || ' hours') AS corrected_end_time, -- Initialize resource last-end-time trackers CASE WHEN rd."主工序" <> 'Test' THEN STRFTIME('%Y-%m-%d %H:%M:%S', COALESCE(rd."实际开始时间", rd."计划开始时间", STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'localtime')), '+' || rd.total_hours || ' hours') ELSE NULL END AS line_last_end, CASE WHEN rd."主工序" = 'Test' THEN STRFTIME('%Y-%m-%d %H:%M:%S', COALESCE(rd."实际开始时间", rd."计划开始时间", STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'localtime')), '+' || rd.total_hours || ' hours') ELSE NULL END AS item_test_last_end FROM RankedData rd WHERE rd.global_rank = 1 UNION ALL -- Recursive Member: Process subsequent operations one by one SELECT rd.global_rank, rd."批次", rd."线体", rd."单板代码", rd."主工序", rd.op_rank_in_batch, rd.total_hours, -- Determine the corrected start time based on dependencies ( SELECT MAX(ts) FROM ( -- Dependency 1: Previous operation in the same batch SELECT cs.corrected_end_time FROM CorrectedSchedule cs WHERE cs."批次" = rd."批次" AND cs.op_rank_in_batch = rd.op_rank_in_batch - 1 UNION ALL -- Dependency 2: Resource availability (line or test) SELECT CASE WHEN rd."主工序" = 'Test' THEN (SELECT MAX(cs2.item_test_last_end) FROM CorrectedSchedule cs2 WHERE cs2."单板代码" = rd."单板代码") ELSE (SELECT MAX(cs2.line_last_end) FROM CorrectedSchedule cs2 WHERE cs2."线体" = rd."线体") END UNION ALL -- Dependency 3: Its own original start time (or now if null) SELECT COALESCE(rd."实际开始时间", rd."计划开始时间", STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'localtime')) ) AS times(ts) ) AS corrected_start_time, -- Calculate the new end time based on the corrected start time STRFTIME('%Y-%m-%d %H:%M:%S', (SELECT MAX(ts) FROM ( SELECT cs.corrected_end_time FROM CorrectedSchedule cs WHERE cs."批次" = rd."批次" AND cs.op_rank_in_batch = rd.op_rank_in_batch - 1 UNION ALL SELECT CASE WHEN rd."主工序" = 'Test' THEN (SELECT MAX(cs2.item_test_last_end) FROM CorrectedSchedule cs2 WHERE cs2."单板代码" = rd."单板代码") ELSE (SELECT MAX(cs2.line_last_end) FROM CorrectedSchedule cs2 WHERE cs2."线体" = rd."线体") END UNION ALL SELECT COALESCE(rd."实际开始时间", rd."计划开始时间", STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'localtime')) ) AS times(ts)), '+' || rd.total_hours || ' hours' ) AS corrected_end_time, -- Update resource trackers for the next iteration CASE WHEN rd."主工序" <> 'Test' THEN STRFTIME('%Y-%m-%d %H:%M:%S', (SELECT MAX(ts) FROM (SELECT cs.corrected_end_time FROM CorrectedSchedule cs WHERE cs."批次" = rd."批次" AND cs.op_rank_in_batch = rd.op_rank_in_batch - 1 UNION ALL SELECT CASE WHEN rd."主工序" = 'Test' THEN (SELECT MAX(cs2.item_test_last_end) FROM CorrectedSchedule cs2 WHERE cs2."单板代码" = rd."单板代码") ELSE (SELECT MAX(cs2.line_last_end) FROM CorrectedSchedule cs2 WHERE cs2."线体" = rd."线体") END UNION ALL SELECT COALESCE(rd."实际开始时间", rd."计划开始时间", STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'localtime'))) AS times(ts)), '+' || rd.total_hours || ' hours') ELSE (SELECT MAX(cs2.line_last_end) FROM CorrectedSchedule cs2 WHERE cs2."线体" = rd."线体") END, CASE WHEN rd."主工序" = 'Test' THEN STRFTIME('%Y-%m-%d %H:%M:%S', (SELECT MAX(ts) FROM (SELECT cs.corrected_end_time FROM CorrectedSchedule cs WHERE cs."批次" = rd."批次" AND cs.op_rank_in_batch = rd.op_rank_in_batch - 1 UNION ALL SELECT CASE WHEN rd."主工序" = 'Test' THEN (SELECT MAX(cs2.item_test_last_end) FROM CorrectedSchedule cs2 WHERE cs2."单板代码" = rd."单板代码") ELSE (SELECT MAX(cs2.line_last_end) FROM CorrectedSchedule cs2 WHERE cs2."线体" = rd."线体") END UNION ALL SELECT COALESCE(rd."实际开始时间", rd."计划开始时间", STRFTIME('%Y-%m-%d %H:%M:%S', 'now', 'localtime'))) AS times(ts)), '+' || rd.total_hours || ' hours') ELSE (SELECT MAX(cs2.item_test_last_end) FROM CorrectedSchedule cs2 WHERE cs2."单板代码" = rd."单板代码") END FROM RankedData rd JOIN CorrectedSchedule cs ON rd.global_rank = cs.global_rank + 1 ), -- Step 4: Combine final schedule with other data and calculate daily outputs FinalData AS ( SELECT rd.*, cs.corrected_start_time, cs.corrected_end_time, CASE WHEN rd."入库工序" = '是' THEN DATE(cs.corrected_end_time) ELSE NULL END AS "入库时间" FROM RankedData rd JOIN CorrectedSchedule cs ON rd.global_rank = cs.global_rank ), -- Step 5: Calculate the output for each of the next 7 days DailyOutputCalculation AS ( SELECT f.*, (SELECT "计调员" FROM part_category pc WHERE pc."单板代码" LIKE f."单板代码" || '%' AND pc."工厂" = f."工厂" LIMIT 1) AS "责任人", -- Logic to distribute remaining quantity over the plan duration for the next 7 days CASE WHEN f."入库工序" = '是' AND JULIANDAY(DATE('now', '+0 days')) BETWEEN JULIANDAY(f.corrected_start_time) AND JULIANDAY(f.corrected_end_time) THEN ROUND(f."剩余数量" / (JULIANDAY(f.corrected_end_time) - JULIANDAY(f.corrected_start_time) + 1)) ELSE 0 END AS day_1_output, CASE WHEN f."入库工序" = '是' AND JULIANDAY(DATE('now', '+1 days')) BETWEEN JULIANDAY(f.corrected_start_time) AND JULIANDAY(f.corrected_end_time) THEN ROUND(f."剩余数量" / (JULIANDAY(f.corrected_end_time) - JULIANDAY(f.corrected_start_time) + 1)) ELSE 0 END AS day_2_output, CASE WHEN f."入库工序" = '是' AND JULIANDAY(DATE('now', '+2 days')) BETWEEN JULIANDAY(f.corrected_start_time) AND JULIANDAY(f.corrected_end_time) THEN ROUND(f."剩余数量" / (JULIANDAY(f.corrected_end_time) - JULIANDAY(f.corrected_start_time) + 1)) ELSE 0 END AS day_3_output, CASE WHEN f."入库工序" = '是' AND JULIANDAY(DATE('now', '+3 days')) BETWEEN JULIANDAY(f.corrected_start_time) AND JULIANDAY(f.corrected_end_time) THEN ROUND(f."剩余数量" / (JULIANDAY(f.corrected_end_time) - JULIANDAY(f.corrected_start_time) + 1)) ELSE 0 END AS day_4_output, CASE WHEN f."入库工序" = '是' AND JULIANDAY(DATE('now', '+4 days')) BETWEEN JULIANDAY(f.corrected_start_time) AND JULIANDAY(f.corrected_end_time) THEN ROUND(f."剩余数量" / (JULIANDAY(f.corrected_end_time) - JULIANDAY(f.corrected_start_time) + 1)) ELSE 0 END AS day_5_output, CASE WHEN f."入库工序" = '是' AND JULIANDAY(DATE('now', '+5 days')) BETWEEN JULIANDAY(f.corrected_start_time) AND JULIANDAY(f.corrected_end_time) THEN ROUND(f."剩余数量" / (JULIANDAY(f.corrected_end_time) - JULIANDAY(f.corrected_start_time) + 1)) ELSE 0 END AS day_6_output, CASE WHEN f."入库工序" = '是' AND JULIANDAY(DATE('now', '+6 days')) BETWEEN JULIANDAY(f.corrected_start_time) AND JULIANDAY(f.corrected_end_time) THEN ROUND(f."剩余数量" / (JULIANDAY(f.corrected_end_time) - JULIANDAY(f.corrected_start_time) + 1)) ELSE 0 END AS day_7_output FROM FinalData f ) -- Final Step: Insert the processed data into the permanent table INSERT INTO daily_output_plan_final ( "批次", "指令", "线体", "单板代码", "单板名称", "计划数量", "产出数量", "剩余数量", "计划开始时间", "计划结束时间", "实际开始时间", "修正后计划开始时间", "修正后计划结束时间", "主工序", "工序序号", "入库工序", "入库时间", "产品大类", "工厂", "责任人", "day_1_output", "day_2_output", "day_3_output", "day_4_output", "day_5_output", "day_6_output", "day_7_output" ) SELECT "批次", "指令", "线体", "单板代码", "单板名称", "计划数量", "产出数量", "剩余数量", "计划开始时间", "计划结束时间", "实际开始时间", corrected_start_time AS "修正后计划开始时间", corrected_end_time AS "修正后计划结束时间", "主工序", "工序序号", "入库工序", "入库时间", "产品大类", "工厂", "责任人", day_1_output, day_2_output, day_3_output, day_4_output, day_5_output, day_6_output, day_7_output FROM DailyOutputCalculation;
最新发布
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值