AI智能
改变未来

Oracle高级语句Model语句简介

文章目录

  • 一.以一个例子来认识Model子句
  • 二.位置标记
  • 三.符号标记
  • 四.for循环
  • 五.聚合

备注:测试数据库版本为Oracle 11g R2

这个blog我们来聊聊Oracle的Model子句
Oracle的Model子句非常强大,本文章简单介绍下Model

Model子句语法:

MODEL[][][MAIN ][PARTITION BY ()]DIMENSION BY ()MEASURES ()[][RULES](, ,.., )::=::= RETURN {ALL|UPDATED} ROWS::=[IGNORE NAV | [KEEP NAV][UNIQUE DIMENSION | UNIQUE SINGLE REFERENCE]::=[UPDATE | UPSERT | UPSERT ALL][AUTOMATIC ORDER | SEQUENTIAL ORDER][ITERATE ()  [UNTIL ]]::= REFERENCE ON ON ()DIMENSION BY () MEASURES ()

一.以一个例子来认识Model子句

看到上面Model复杂的语法,头都大了,不清楚如何使用
我们先简单的捋一捋Model子句是用来解决什么问题的

上面是一个excel表格,记录了每周口罩的进货量、销售量和库存
本周库存 = 本周进货量-本周销售额+上周库存
在excel中,我们可以用上图中的公式,来计算每周的库存

Oracle中,Model子句就是为了解决这类跨行引用
测试数据:

create table sales_fact(prod      varchar2(20),--产品year    number,      --年week    number,      --月sale    number,      --销售额receipts       number       --进货量);insert into sales_fact values (\'口罩\',2020,1,100,200);insert into sales_fact values (\'口罩\',2020,2,100,200);insert into sales_fact values (\'口罩\',2020,3,150,300);insert into sales_fact values (\'口罩\',2020,4,1000,5000);insert into sales_fact values (\'口罩\',2020,5,2000,10000);insert into sales_fact values (\'口罩\',2020,6,3000,0);insert into sales_fact values (\'口罩\',2020,7,5000,0);insert into sales_fact values (\'口罩\',2020,8,10000,10000);insert into sales_fact values (\'口罩\',2020,9,100000,100000);insert into sales_fact values (\'口罩\',2020,10,100000,100000);insert into sales_fact values (\'口罩\',2020,11,100000,100000);insert into sales_fact values (\'口罩\',2020,12,100000,100000);insert into sales_fact values (\'口罩\',2020,13,100000,100000);insert into sales_fact values (\'口罩\',2020,14,100000,100000);commit;

我们通过Model子句可以很轻易的实现这个需求:

select prod ,year ,week ,sale ,    --销售量receipts, --进货量inventory --库存量from sales_factwhere 1 = 1model return updated rowspartition by(prod)dimension by(year,week)measures(0 inventory,sale,receipts) rules automaticorder(inventory[year,week] = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)] )order by prod,year,week;
SQL> select prod ,2         year ,3         week ,4         sale ,    --销售量5         receipts, --进货量6         inventory --库存量7  from sales_fact8  where 1 = 19  model return updated rows10  partition by(prod)11  dimension by(year,week)12  measures(0 inventory,sale,receipts) rules automatic13  order(inventory[year,week] = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)] )14  order by prod,year,week;PROD                       YEAR       WEEK       SALE   RECEIPTS  INVENTORY-------------------- ---------- ---------- ---------- ---------- ----------口罩                       2020          1        100        200        100口罩                       2020          2        100        200        200口罩                       2020          3        150        300        350口罩                       2020          4       1000       5000       4350口罩                       2020          5       2000      10000      12350口罩                       2020          6       3000          0       9350口罩                       2020          7       5000          0       4350口罩                       2020          8      10000      10000       4350口罩                       2020          9     100000     100000       4350口罩                       2020         10     100000     100000       4350口罩                       2020         11     100000     100000       4350口罩                       2020         12     100000     100000       4350口罩                       2020         13     100000     100000       4350口罩                       2020         14     100000     100000       435014 rows selected
子句 说明
partition by(prod) 将prod列指定为分区列
dimension by(year, week) 指定year,week为维度列
measures(0 inventory, sale, receipts) 将inventory,sales,receipts列指定为度量值列
order(inventory [ year, week ] =
nvl(inventory [ cv(year), cv(week) – 1 ], 0) – sale [ cv(year), cv(week) ] +
receipts [ cv(year), cv(week) ])
规则类似于一个公式

prod分区,与Oracle其它分析函数的分区相同,分区列值相同的所有行被认为是在同一个分区中
year、week为维度,维度列唯一辩识每一行,产品为口罩,每年每周只有一行数据
measures(0 inventory, sale, receipts)表示 inventory, sale, receipts三列为计算的列值
计算公式这个,可以类比excel截图中的公式来看, 0 inventory 代表如果找不到上周的库存,默认值为0

二.位置标记

假设2020年第8周,口罩销售量和进货量猛增,有部分数据没有录入系统
其实真实的进货量为300000,销售量也为200000

--公式列直接修改数据,这也太方便了吧select prod ,year ,week ,sale ,    --销售量receipts, --进货量inventory --库存量from sales_factwhere 1 = 1model return updated rowspartition by(prod)dimension by(year,week)measures(0 inventory,sale,receipts) rules automaticorder(inventory[year,week] = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)],sale[2020,8] = 200000, receipts[2020,8] = 300000)order by prod,year,week;
--公式列直接修改数据,这也太方便了吧--sale[2020,8] = 200000, receipts[2020,8] = 300000SQL> select prod ,2         year ,3         week ,4         sale ,    --销售量5         receipts, --进货量6         inventory --库存量7  from sales_fact8  where 1 = 19  model return updated rows10  partition by(prod)11  dimension by(year,week)12  measures(0 inventory,sale,receipts) rules automatic13  order(inventory[year,week] = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)],sale[2020,8] = 200000, receipts[2020,8] = 300000)14  order by prod,year,week;PROD                       YEAR       WEEK       SALE   RECEIPTS  INVENTORY-------------------- ---------- ---------- ---------- ---------- ----------口罩                       2020          1        100        200        100口罩                       2020          2        100        200        200口罩                       2020          3        150        300        350口罩                       2020          4       1000       5000       4350口罩                       2020          5       2000      10000      12350口罩                       2020          6       3000          0       9350口罩                       2020          7       5000          0       4350口罩                       2020          8     200000     300000     104350口罩                       2020          9     100000     100000     104350口罩                       2020         10     100000     100000     104350口罩                       2020         11     100000     100000     104350口罩                       2020         12     100000     100000     104350口罩                       2020         13     100000     100000     104350口罩                       2020         14     100000     100000     10435014 rows selected--可以看到model子句只是改了输出,原表的数据并没有更新SQL> select * from sales_fact;PROD                       YEAR       WEEK       SALE   RECEIPTS-------------------- ---------- ---------- ---------- ----------口罩                       2020          1        100        200口罩                       2020          2        100        200口罩                       2020          3        150        300口罩                       2020          4       1000       5000口罩                       2020          5       2000      10000口罩                       2020          6       3000          0口罩                       2020          7       5000          0口罩                       2020          8      10000      10000口罩                       2020          9     100000     100000口罩                       2020         10     100000     100000口罩                       2020         11     100000     100000口罩                       2020         12     100000     100000口罩                       2020         13     100000     100000口罩                       2020         14     100000     10000014 rows selected

假设15周的数据忘记记录了,在原有的基础上加上15周的数据
2020年第15周销售额 100000,进货量100000

--15周数据不存在--我直接在公式列指定即可,马上就有数据了select prod ,year ,week ,sale ,    --销售量receipts, --进货量inventory --库存量from sales_factwhere 1 = 1model return updated rowspartition by(prod)dimension by(year,week)measures(0 inventory,sale,receipts) rules automaticorder(inventory[year,week] = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)],sale[2020,8] = 200000, receipts[2020,8] = 300000,sale[2020,15] = 100000, receipts[2020,15] = 100000)order by prod,year,week;
SQL> --15周数据不存在SQL> --我直接在公式列指定即可,马上就有数据了SQL> select prod ,2         year ,3         week ,4         sale ,    --销售量5         receipts, --进货量6         inventory --库存量7  from sales_fact8  where 1 = 19  model return updated rows10  partition by(prod)11  dimension by(year,week)12  measures(0 inventory,sale,receipts) rules automatic13  order(inventory[year,week] = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)],sale[2020,8] = 200000, receipts[2020,8] = 300000,sale[2020,15] = 100000, receipts[2020,15] = 100000)14  order by prod,year,week;PROD                       YEAR       WEEK       SALE   RECEIPTS  INVENTORY-------------------- ---------- ---------- ---------- ---------- ----------口罩                       2020          1        100        200        100口罩                       2020          2        100        200        200口罩                       2020          3        150        300        350口罩                       2020          4       1000       5000       4350口罩                       2020          5       2000      10000      12350口罩                       2020          6       3000          0       9350口罩                       2020          7       5000          0       4350口罩                       2020          8     200000     300000     104350口罩                       2020          9     100000     100000     104350口罩                       2020         10     100000     100000     104350口罩                       2020         11     100000     100000     104350口罩                       2020         12     100000     100000     104350口罩                       2020         13     100000     100000     104350口罩                       2020         14     100000     100000     104350口罩                       2020         15     100000     100000     10435015 rows selected--可以看到model子句只是改了输出,原表的数据并没有更新SQL> select * from sales_fact;PROD                       YEAR       WEEK       SALE   RECEIPTS-------------------- ---------- ---------- ---------- ----------口罩                       2020          1        100        200口罩                       2020          2        100        200口罩                       2020          3        150        300口罩                       2020          4       1000       5000口罩                       2020          5       2000      10000口罩                       2020          6       3000          0口罩                       2020          7       5000          0口罩                       2020          8      10000      10000口罩                       2020          9     100000     100000口罩                       2020         10     100000     100000口罩                       2020         11     100000     100000口罩                       2020         12     100000     100000口罩                       2020         13     100000     100000口罩                       2020         14     100000     10000014 rows selected

三.符号标记

此时需求14-16周的销售额和进货量都是录入数据的1.2倍

--符号标记不同于位置标记,如果不存在不会新增--此列自己指定了每个公式的order by  没有用 automatic order,但是推荐使用 automatic order,Oracle还是很智能的--注释了return updated rows之后,显示所有select prod ,year ,week ,sale ,    --销售量receipts, --进货量inventory --库存量from sales_factwhere 1 = 1model --return updated rowspartition by(prod)dimension by(year,week)measures(0 inventory,sale,receipts)rules (--inventory[year,week] order by year,week = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)] ,sale[year in (2020),week in (14,15,16)] order by year,week = sale[cv(year),cv(week)]*1.2,receipts[year in (2020),week in (14,15,16)] order by year,week = receipts[cv(year),cv(week)]*1.2)order by prod,year,week;--符号标记不同于位置标记,如果不存在不会新增--此列自己指定了每个公式的order by  没有用 automatic order,但是推荐使用 automatic order,Oracle还是很智能的--加上return updated rows之后,只显示更改的select prod ,year ,week ,sale ,    --销售量receipts, --进货量inventory --库存量from sales_factwhere 1 = 1model return updated rowspartition by(prod)dimension by(year,week)measures(0 inventory,sale,receipts)rules (--inventory[year,week] order by year,week = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)] ,sale[year in (2020),week in (14,15,16)] order by year,week = sale[cv(year),cv(week)]*1.2,receipts[year in (2020),week in (14,15,16)] order by year,week = receipts[cv(year),cv(week)]*1.2)order by prod,year,week;
SQL> --符号标记不同于位置标记,如果不存在不会新增SQL> --此列自己指定了每个公式的order by  没有用 automatic order,但是推荐使用 automatic order,Oracle还是很智能的SQL> --注释了return updated rows之后,显示所有SQL> select prod ,2         year ,3         week ,4         sale ,    --销售量5         receipts, --进货量6         inventory --库存量7  from sales_fact8  where 1 = 19  model --return updated rows10  partition by(prod)11  dimension by(year,week)12  measures(0 inventory,sale,receipts)13  rules (--inventory[year,week] order by year,week = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)] ,14        sale[year in (2020),week in (14,15,16)] order by year,week = sale[cv(year),cv(week)]*1.2,15        receipts[year in (2020),week in (14,15,16)] order by year,week = receipts[cv(year),cv(week)]*1.216        )17  order by prod,year,week;PROD                       YEAR       WEEK       SALE   RECEIPTS  INVENTORY-------------------- ---------- ---------- ---------- ---------- ----------口罩                       2020          1        100        200          0口罩                       2020          2        100        200          0口罩                       2020          3        150        300          0口罩                       2020          4       1000       5000          0口罩                       2020          5       2000      10000          0口罩                       2020          6       3000          0          0口罩                       2020          7       5000          0          0口罩                       2020          8      10000      10000          0口罩                       2020          9     100000     100000          0口罩                       2020         10     100000     100000          0口罩                       2020         11     100000     100000          0口罩                       2020         12     100000     100000          0口罩                       2020         13     100000     100000          0口罩                       2020         14     120000     120000          014 rows selectedSQL> --符号标记不同于位置标记,如果不存在不会新增SQL> --此列自己指定了每个公式的order by  没有用 automatic order,但是推荐使用 automatic order,Oracle还是很智能的SQL> --加上return updated rows之后,只显示更改的SQL> select prod ,2         year ,3         week ,4         sale ,    --销售量5         receipts, --进货量6         inventory --库存量7  from sales_fact8  where 1 = 19  model return updated rows10  partition by(prod)11  dimension by(year,week)12  measures(0 inventory,sale,receipts)13  rules (--inventory[year,week] order by year,week = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)] ,14        sale[year in (2020),week in (14,15,16)] order by year,week = sale[cv(year),cv(week)]*1.2,15        receipts[year in (2020),week in (14,15,16)] order by year,week = receipts[cv(year),cv(week)]*1.216        )17  order by prod,year,week;PROD                       YEAR       WEEK       SALE   RECEIPTS  INVENTORY-------------------- ---------- ---------- ---------- ---------- ----------口罩                       2020         14     120000     120000          0

四.for循环

假设现在有需求,2020年第8周开始,每周进货量和销售额都是150000

for dimension for <value1> to <value2>[increment | decrement] <value3>
--此时不存在的15周也出来了--for循环可以减少很多代码量select prod ,year ,week ,sale ,    --销售量receipts, --进货量inventory --库存量from sales_factwhere 1 = 1model return updated rowspartition by(prod)dimension by(year,week)measures(0 inventory,sale,receipts)rules automatic order(sale[2020,for week from 8 to 15 increment  1]  = 150000,receipts[2020,for week from 8 to 15 increment  1]  = 150000,inventory[year,week]  = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)])order by prod,year,week;
SQL> --此时不存在的15周也出来了SQL> --for循环可以减少很多代码量SQL> select prod ,2         year ,3         week ,4         sale ,    --销售量5         receipts, --进货量6         inventory --库存量7  from sales_fact8  where 1 = 19  model return updated rows10  partition by(prod)11  dimension by(year,week)12  measures(0 inventory,sale,receipts)13  rules automatic order(14        sale[2020,for week from 8 to 15 increment  1]  = 150000,15        receipts[2020,for week from 8 to 15 increment  1]  = 150000,16        inventory[year,week]  = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)]17        )18  order by prod,year,week;PROD                       YEAR       WEEK       SALE   RECEIPTS  INVENTORY-------------------- ---------- ---------- ---------- ---------- ----------口罩                       2020          1        100        200        100口罩                       2020          2        100        200        200口罩                       2020          3        150        300        350口罩                       2020          4       1000       5000       4350口罩                       2020          5       2000      10000      12350口罩                       2020          6       3000          0       9350口罩                       2020          7       5000          0       4350口罩                       2020          8     150000     150000       4350口罩                       2020          9     150000     150000       4350口罩                       2020         10     150000     150000       4350口罩                       2020         11     150000     150000       4350口罩                       2020         12     150000     150000       4350口罩                       2020         13     150000     150000       4350口罩                       2020         14     150000     150000       4350口罩                       2020         15     150000     150000       435015 rows selected

五.聚合

Model子句还可以配合avg、sum、max等函数一起使用

select prod ,year ,week ,sale ,    --销售量receipts, --进货量inventory, --库存量avg_inventory , --平均库存max_sale      --单周最大销售额from sales_factwhere 1 = 1model return updated rowspartition by(prod)dimension by(year,week)measures(0 inventory,sale,receipts,0 avg_inventory,0 max_sale) rules automaticorder(inventory[year,week] = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)],avg_inventory[year,ANY] = round(avg(inventory)[cv(year),week],2),max_sale[year,ANY] = max(sale)[cv(year),week])order by prod,year,week;
SQL> --在求库存的基础上,增加平均库存及最大销售额SQL> select prod ,2         year ,3         week ,4         sale ,    --销售量5         receipts, --进货量6         inventory, --库存量7         avg_inventory , --平均库存8         max_sale      --单周最大销售额9  from sales_fact10  where 1 = 111  model return updated rows12  partition by(prod)13  dimension by(year,week)14  measures(0 inventory,sale,receipts,0 avg_inventory,0 max_sale) rules automatic15  order(inventory[year,week] = nvl(inventory[cv(year),cv(week) - 1],0) - sale[cv(year),cv(week)] + receipts[cv(year),cv(week)],16        avg_inventory[year,ANY] = round(avg(inventory)[cv(year),week],2),17        max_sale[year,ANY] = max(sale)[cv(year),week]18        )19  order by prod,year,week;PROD                       YEAR       WEEK       SALE   RECEIPTS  INVENTORY AVG_INVENTORY   MAX_SALE-------------------- ---------- ---------- ---------- ---------- ---------- ------------- ----------口罩                       2020          1        100        200        100       4392.86     100000口罩                       2020          2        100        200        200       4392.86     100000口罩                       2020          3        150        300        350       4392.86     100000口罩                       2020          4       1000       5000       4350       4392.86     100000口罩                       2020          5       2000      10000      12350       4392.86     100000口罩                       2020          6       3000          0       9350       4392.86     100000口罩                       2020          7       5000          0       4350       4392.86     100000口罩                       2020          8      10000      10000       4350       4392.86     100000口罩                       2020          9     100000     100000       4350       4392.86     100000口罩                       2020         10     100000     100000       4350       4392.86     100000口罩                       2020         11     100000     100000       4350       4392.86     100000口罩                       2020         12     100000     100000       4350       4392.86     100000口罩                       2020         13     100000     100000       4350       4392.86     100000口罩                       2020         14     100000     100000       4350       4392.86     10000014 rows selected
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Oracle高级语句Model语句简介