搞笑
可能这几天总是跟俞佳妮打交道,昨天晚上做梦竟然梦到她了
好像在一个学校里,好像是去上课的样子
还有阮菲菲也出现了
阮菲菲在梦里还对人开玩笑的说是我女朋友了-_-!
可恶啊,人家都已经身怀几甲了,罪过罪过……哦弥陀佛,善哉善哉
呵呵,莫名其妙啊哈哈
记录学习
搞笑
可能这几天总是跟俞佳妮打交道,昨天晚上做梦竟然梦到她了
好像在一个学校里,好像是去上课的样子
还有阮菲菲也出现了
阮菲菲在梦里还对人开玩笑的说是我女朋友了-_-!
可恶啊,人家都已经身怀几甲了,罪过罪过……哦弥陀佛,善哉善哉
呵呵,莫名其妙啊哈哈
1:介绍关于行列转换前的通用知识
Pivot查询是这样的,当你想要取出一些如下的数据时:
C1 C2 C3
������������
a1 b1 x1
a1 b1 x2
a1 b1 x3
想按如下格式显示:
C1 C2 C3(1) C3(2) C3(3)
A1 b1 x1 x2 x3
这样就将行转变成了列。
2:
在我们的日常开发中,经常会遇到这样的情况,就是分类汇总,而用一般的SQL写出的程序,数据是向行的方向展开的,但大部分报表的设计是希望向列的方向展开,这样的话,行列转换是非常必要和有用的!
3:通用转换包的实现
首先看一段代码
这段代码是将部门的收入前3名选择出来并用列的形式显示出来。(关于partiton by ,order by,
row_number over请参考相关分析函数的说明
下边是关于通包的包头说明:
create or replace package r_c_pkg
as
type refcursor is ref cursor; --定义一个结果信类型,用来返回结果集
type array is table of varchar2(30);--定义表结构类型。
procedure dbpivot(p_class_code_array in array ,
p_query in varchar2,
p_row_value in array,
p_class_value in array,
p_sum_row in varchar2,
p_cursor in out refcursor);
end ;
��������������
包体:
create or replace package body r_c_pkg
as
procedure dbpivot(p_class_code_array in array ,--存储类编号的值
p_query in varchar2,--必须有一项为CLASS_code,别名也可以
p_row_value in array,--需要做为列的值
p_class_value in array,--需要根据分类取的值
p_sum_row in varchar2,--如果还要在进行SUM的一些值
p_cursor in out refcursor)
as
------------------------------------------------
/*参数示例
p_class_code=> r_c_pkg.array('001','002','005') -其中001,002为需要分列显示的分类值
p_query =>'select a.pdep_code,c.class_code,sum(a.c_pay) as c_pay,sum(a.base_qty) as b_qty,
row_number()over
(partition by a.pdep_code
order by c.class_code nulls last) seq
from user_charge_tbl a,user_tbl c
where a.pdep_code='18' and a.user_id=c.user_id
group by a.pdep_code,c.class_code
'
p_row_value => r_c_pkg.array('pdep_code') 所有查询最前边那个GROUP BY 对像
p_class_value => r_c_pkg.arry('c_pay','b_qty') 是那个CLASS――CODE后边需要显示的值
p_cursor =>r_c_pkg.refcursor 目的是将得到的结果返回出来
p_sum_row=>'sum(base_cost),sum(f_cost)
*/
-------------------------------------------------
v_ncol_count number;
l_query long ;
v_class LONG;
l_row_value varchar2(500);
v_test_string varchar2(500);
begin
l_query:='select'||' ' ;
for j in 1..p_row_value.count -1
loop
l_row_value:=l_row_value||' '||p_row_value(j)||',';
end loop;
l_query:=l_query||l_row_value ;
--------------mxfhhh20060330
--l_query:=rtrim(l_query,',');
--------------mxfhhh20060330
for i in 1..p_class_code_array.count
loop
for k in 1..p_class_value.count-1
loop
--max(decode(class_code,'005',c_pay,0))f005
v_class:=v_class||' '||'max(decode(class_code,'||p_class_code_array(i)||
','||p_class_value(k)||',0))'||
' f'||p_class_code_array(i)||p_class_value(k)||',';
end loop;
end loop;
l_query:=l_query||v_class;
if p_sum_row='' then
l_query:=rtrim(l_query,',')||' from('||p_query||') group by ';
else
l_query:=l_query||p_sum_row||' from('||p_query||') group by ';
end if;
for j in 1..p_row_value.count
loop
l_query:=l_query||p_row_value(j);
v_test_string :=p_row_value(j)||v_test_string;
end loop;
l_query:=rtrim(l_query,',');
execute immediate 'alter session set cursor_sharing=force';
open p_cursor for l_query;
execute immediate 'alter session set cursor_sharing=exact';
---select user_id into l_query from user_tbl;
end;
end;
整个包的目的是动态生成您需要的行列转换内容,并返回结果集.
动态生成的SQL语句如下所示:
select sarea_code,
max(decode(class_code,004,c_pay,0)) f004c_pay,
max(decode(class_code,004,b_qty,0)) f004b_qty,
max(decode(class_code,005,c_pay,0)) f005c_pay,
max(decode(class_code,005,b_qty,0)) f005b_qty,
max(decode(class_code,006,c_pay,0)) f006c_pay,
max(decode(class_code,006,b_qty,0)) f006b_qty,
max(decode(class_code,007,c_pay,0)) f007c_pay,
max(decode(class_code,007,b_qty,0)) f007b_qty,
max(decode(class_code,008,c_pay,0)) f008c_pay,
max(decode(class_code,008,b_qty,0)) f008b_qty,
sum(base_cost),
sum(f_cost)
from
(
select a.sarea_code,c.class_code,sum(a.c_pay) as c_pay,
sum(a.base_qty+a.closs_qty+a.ex_qty+a.ad_qty) as b_qty,sum(a.base_cost) as base_cost,
sum(a.fadjust_cost) as f_cost,
row_number()over
(partition by a.sarea_code
order by c.class_code nulls last) seq
from user_charge_tbl a,user_tbl c
where a.sarea_code>='18001' and a.sarea_code<='18002' and a.user_id=c.user_id
group by a.sarea_code,c.class_code
)
group by sarea_code
以上程序根据工作需要而完成的,希望对那些报表设计有需要的同行有帮助。
参考书:oracle-one-on-one
--
Guyq <guyq@dealeasy.com>
假如有如下表,其中各个i值对应的行数是不定的
SQL> select * from t;
I A D
---------- ---------- -------------------
1 b 2008-03-27 10:55:42
1 a 2008-03-27 10:55:46
1 d 2008-03-27 10:55:30
2 z 2008-03-27 10:55:55
2 t 2008-03-27 10:55:59
要获得如下结果,注意字符串需要按照D列的时间排序:
1 d,b,a
2 z,t
这是一个比较典型的行列转换,有好几种实现方法
1.自定义函数实现
create or replace function my_concat(n number)
return varchar2
is
type typ_cursor is ref cursor;
v_cursor typ_cursor;
v_temp varchar2(10);
v_result varchar2(4000):= '';
v_sql varchar2(200);
begin
v_sql := 'select a from t where i=' || n ||' order by d';
open v_cursor for v_sql;
loop
fetch v_cursor into v_temp;
exit when v_cursor%notfound;
v_result := v_result ||',' || v_temp;
end loop;
return substr(v_result,2);
end;
SQL> select i,my_concat(i) from t group by i;
I MY_CONCAT(I)
---------- --------------------
1 d,b,a
2 z,t
虽然这种方式可以实现需求,但是如果表t的数据量很大,i的值又很多的情况下,因为针对每个i值都要执行一句select,扫描和排序的次数和i的值成正比,性能会非常差。
2.使用sys_connect_by_path
select i,ltrim(max(sys_connect_by_path(a,',')),',') a
from
(
select i,a,d,min(d) over(partition by i) d_min,
(row_number() over(order by i,d))+(dense_rank() over (order by i)) numid
from t
)
start with d=d_min connect by numid-1=prior numid
group by i;
从执行计划上来看,这种方式只需要扫描两次表,比自定义函数的方法,效率要高很多,尤其是表中数据量较大的时候:
eplan1
3.使用wm_sys.wm_concat
这个函数也可以实现类似的行列转换需求,但是似乎没有办法做到直接根据另外一列排序,所以需要先通过子查询或者临时表排好序
SQL> select i,wmsys.wm_concat(a) from t group by i;
I WMSYS.WM_CONCAT(A)
---------- --------------------
1 b,a,d
2 z,t
SQL> select i,wmsys.wm_concat(a)
2 from
3 (select * from t order by i,d)
4 group by i;
I WMSYS.WM_CONCAT(A)
---------- --------------------
1 d,b,a
2 z,t
执行计划上看,只需要做一次表扫描就可以了,但是这个函数是加密过的,执行计划并不能显示函数内部的操作。
--
Guyq <guyq@dealeasy.com>
replaceNullToSpace: aString
"Written By fmg33201 27 April 2007 17:58."
"16r0000の文字をスペースに置き換える。"
^self dataSetExcelClass new replaceNullToSpace: aString
--
Guyq <guyq@dealeasy.com>
┏━━━━━━┳━━━━━┳━━━━━┓
┃ 重新生成 ┃ 需求更改 ┃ 净改变 ┃
┏━━━━━━╋━━━━━━╋━━━━━╋━━━━━┫
┃ 库存未了结 ┃ ┃ ┃ ┃
┃ 订单被更新 ┃ 是 ┃ 是 ┃ 是 ┃
┣━━━━━━╋━━━━━━╋━━━━━╋━━━━━┫
┃ 全部主生产 ┃ ┃ ┃ ┃
┃ 计划被展开 ┃ 是 ┃ 否 ┃ 否 ┃
┣━━━━━━╋━━━━━━╋━━━━━╋━━━━━┫
┃ MRP运行 ┃ 每周 每二周┃ 每日 ┃ ┃
┃ 的频度 ┃每月(难得)┃ 每半周 ┃ 每日 ┃
┣━━━━━━╋━━━━━━╋━━━━━╋━━━━━┫
┃ 每一事务被 ┃ ┃ ┃ ┃
┃ 分析的效果 ┃ 否 ┃ 否 ┃ 是 ┃
┗━━━━━━┻━━━━━━┻━━━━━┻━━━━━┛
图6-17 MRP的更新
订货生产作业中的MRP
客户定制产品的制造商曾经迟迟未采用MRP程序。这主要是由于MRP被误
认为只是一种全视界、典型的净、分时段的、多层次技法,因为大多数文献是这样
说的。纯订货生产产品的制造商(真正的单件或小批生产车间),包括船舶、飞机、
特种机床与电子单元、导弹与重型建筑机械,它们难于开发出一传统的MPS;它
们的产品产量很低(即使大于1的话)而且是间歇地生产的(即使多于1次)。其
物料清单零零碎碎地被开发与发放,往往直到该产品被发货才算是最终的与完全的。
设计更改频繁,许多更改发生在接收检验时的最后时刻。
同时,大多数这类制造商正在计划对外购与自制品都只使用毛需求量与很宽松
的提前期。他们只使用手工的或粗糙的计算机子系统,只具有很小的能力去算出已
经可用的物料。因此,他们认识到MRP的逻辑可以应用但并不清楚如何去应用它。
MRP的应用要求:
1、对于重复生产的产品,即便它完全是客户定做的,要有属物料清单。
2、由组件设计按尽可能满足计划人员所需的日程发放部份物料清单以使他们
去订货物料与安排设施。
3、由工程设计、计划、采购与生产人员共用一个物料清单文件。
4、较宽的时段(几周与几月)
5、缓冲度最小的提前期
当客户允许的提前期明显地短于采购与加工物料所需的总时间时,必须在库存
中备有某些外购件与自制件。既然它们的需求不能由标准MRP程序来计算,这些
物料的获得与控制必须通过
1、经典的或分时段的订货点技法(见第5章)
2、在MRP中使用由属MPS驱动的(见第7章)模块式计划用物料清单。
在发放物料清单信息,管理设计更改,处理事务,报告收货与发货,维护准确
的库存与未了结订单状态以及特别是调整能力以处理会变动的负荷等活动中,严格
的纪律是不可缺少的。一个具有重新制订计划能力的一体化的MRP程序对于订货
生产产品不仅是可以应用的,而且是需要的。
重复性制造业中的MRP
难于应用MRP程序的谱中的另一端是重复生产型公司,它们往往在一个流程
中生产大量很不相同的离散产品。典型产品是汽车、家用电器、电视机、无线电设
备、药品、化妆用品以及精细化工产品。这里的基本困难在于传统的MRP对制造
物品需要有离散的订单,而这些公司是用每班或每日的生产速率与到某一具体日期
的累计总量来考虑问题的。
对外购物料没有困难,它们可按通常的方法来计划。计划问题也可通过采用浅
的物料清单与在原料与成品之间不存或少存作为半成品、中间体、子装配件等产品
的存货而大大简化。图6-18表示通过使用作业天数、需求、收货与已计划订货
(要补与开始)等的累计总量可以使MRP如何适应于重复性制造。注意"将收"
与"累计将收"表示已发放订单的数据;"要补"与"开始"在这时只是已计划而
已。在此期间,有两个节假日,分别落在第16周与第22周。在第18周与22
┏━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓
自制马达┃过┃ 本 周 *假日 ┃
┃ ┣━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┫
#13245 ┃期┃ 14 ┃ 15 ┃ 16 ┃ 17 ┃ 18 ┃ 19 ┃ 20 ┃ 21 ┃ 22*┃
┏━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃累计天数┃ ┃ 69 ┃ 74 ┃ 78 ┃ 83 ┃ 88 ┃ 93 ┃ 98 ┃103 ┃107 ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃ 需求 ┃ ┃ 12 ┃ 12 ┃ 12 ┃ 12 ┃ 17 ┃ 17 ┃ 17 ┃ 17 ┃ 22 ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃累计需求┃ ┃140 ┃152 ┃164 ┃176 ┃193 ┃210 ┃227 ┃244 ┃266 ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃ 将收 ┃ ┃ 12 ┃ 12 ┃ 10 ┃ 12 ┃ ┃ ┃ ┃ ┃ ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃累计将收┃ ┃132 ┃144 ┃154 ┃166 ┃ ┃ ┃ ┃ ┃ ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃ 将有 ┃ 7┃ 7 ┃ 7 ┃ 5 ┃ 5 ┃ 8 ┃ 11 ┃ 14 ┃ 17 ┃ 11 ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃ 要补 ┃ ┃ ┃ ┃ ┃ ┃ 20 ┃ 20 ┃ 20 ┃ 20 ┃ 16 ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃累计要补┃ ┃132 ┃144 ┃154 ┃166 ┃186 ┃206 ┃226 ┃246 ┃262 ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃ 开始 ┃ ┃ ┃ ┃ ┃ 20 ┃ 20 ┃ 20 ┃ 20 ┃ 16 ┃ 20 ┃
┣━━━━╋━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━╋━━┫
┃累计开始┃ ┃144 ┃154 ┃166 ┃186 ┃206 ┃226 ┃246 ┃262 ┃282 ┃
┗━━━━┻━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┛
图6-18 用于重复性制造业的累计式MRP
周,需求将两次增加,每次每周增加5件,但生产只在第18周增加1次,从每周
12件增到20件。这将使库存从7件增长到17件直到需求再次改变,但在这一
库存用完之前生产无需更改。生产与需求可以紧密配合是MRP应用的典型情况。
注意提前期短,这也是重复性制造的典型情况。图中所制造的物品是家用电器中使
用的一种电动机。
当最低生产速率比需求大得多时,该物品将间歇地生产,开工时建立起库存而
停工时库存下降。日产量、日需求与容许的高低库存水平控制着生产运行的时机与
期间数。为显示各种累计总量并按给定的每期间的生产量安排生产日程,计算机程
序只需作很小的修改。
过程工业中的MRP
有各种各样的过程工业,从石油精炼业,它连续地运行专用、设备以生产狭窄
的一大类产品,到食品加工业,它间歇地运行通用设备以生产宽广的多类产品。许
多生产化工品、药品与化妆品的工厂则把几种类型结合起来。间歇地成批生产这类
产品时,可不加修改地应用传统的分时段MRP。使用不常中断的流水线设备来生
产多类产品时(纸、香烟、软饮料),可使用前面为重复性制造讨论过的修改过的
MRP程序。
触媒的裂解单元,管道蒸馏室与精炼作业中的石油化工工厂与粘土、水泥与钢
铁厂的连续作业只要求间歇地进行相当简单的计算以平衡销售、生产与库存,为输
入原料设定流量并提出对包装物料与发货容器还有非常少量的触媒、填料、添加剂
或合金元素的需要量。这种少量的计算要求很小的能力,虽然一种正式的系统方法
总是比零碎的手工技法产生的结果要好些。这些作业中真正的问题在于过程的控制
(从而控制住产品的质量),及时地对原料组成中的变化作出反应,对付无弹性的
能力并在能力太小与太大之间求取一种平衡。
原理28.MRP的逻辑是普遍适用的;它的应用方法要看具体的环境而定。
MRP技法有三件很有价值的工作可做:
1、建议(不是独断)发放订单的恰当时机。
2、指明需要补货的恰当日期并保持这些日期在订单处理期间是有效的。
3、提供信息去帮助能力需求计划与机器和加工中心的加载工作。
MRP不是一个系统。它只是系统中的一种技法(虽然是重要的一种)。其成
功使用取决于本书与第二册中详细讨论的许多因素。MRP的使用中缺乏成功的理
由有:
1、它是一个不完全系统的一部份(见第1章)
2、它被一无效的或管理不善的MPS所驱动(见第7章)
3、数据不准确
4、物料清单没组织好(见本章与第7章)
5、用户不合格