SQL PL/SQL語法手冊
目 錄
第一部分 SQL語法部分 3
一、 CREATE TABLE 語句 3
二、 CREATE SEQUENCE語句 5
三、 CREATE VIEW語句 6
四、 INSERT語句: 7
五、 UPDATE語句: 9
六、 DELETE語句: 10
七、 TRUNCATE語句: 11
八、 各類FUNCTIONS: 12
1. 轉換函數: 12
2. 日期函數 16
3. 字符函數 20
4. 數值函數 28
5. 單行函數: 33
6. 多行函數 35
第二部分 PL/SQL語法部分 41
一、 PL/SQL語言簡介 41
二、 變量說明 48
三、 PL/SQL控制程序流 52
四、 存儲過程 54
五、 存儲函數 54
六、 PACKAGE 54
七、 觸發器 56
八、 應用實例 58
第一部分 SQL語法部分
一、 Create table 語句
語句: CREATE TABLE [schema.]table_name
( { column datatype [DEFAULT expr] [column_constraint] ...
| table_constraint}
[, { column datatype [DEFAULT expr] [column_constraint] ...
| table_constraint} ]...)
[ [PCTFREE integer] [PCTUSED integer]
[INITRANS integer] [MAXTRANS integer]
[TABLESPACE tablespace]
[STORAGE storage_clause]
[ RECOVERABLE | UNRECOVERABLE ]
[ PARALLEL ( [ DEGREE { integer | DEFAULT } ]
[ INSTANCES { integer | DEFAULT } ]
)
| NOPARALLEL ]
[ CACHE | NOCACHE ]
| [CLUSTER cluster (column [, column]...)] ]
[ ENABLE enable_clause
| DISABLE disable_clause ] ...
[AS subquery]
表是Oracle中最重要的數據庫對象,表存儲一些相似的數據集合,這些數據描述成若干列或字段.create table 語句的基本形式用來在數據庫中創建容納數據行的表.create table 語句的簡單形式接收表名,列名,列數據類型和大小.除了列名和描述外,還可以指定約束條件,存儲參數和該表是否是個cluster的一部分.
Schema 用來指定所建表的owner,如不指定則為當前登錄的用戶.
Table_name 用來指定所創建的表名,最長為30個字符,但不可以數字開頭(可為下划線),但不可同其它對象或Oracle的保留字沖突.
Column 用來指定表中的列名,最多254個.
Datatype 用來指定列中存儲什么類型的數據,並保證只有有效的數據才可以輸入.
column_constraint 用來指定列約束,如某一列不可為空,則可指定為not null.
table_constraint 用來指定表約束,如表的主鍵,外鍵等.
Pctfree 用來指定表中數據增長而在Oracle塊中預留的空間. DEFAULT為10%,也就是說該表的每個塊只能使用90%,10%給數據行的增大時使用.
Pctused 用來指定一個水平線,當塊中使用的空間低於該水平線時才可以向該中加入新數據行.
Parallel 用來指定為加速該表的全表掃描可以使用的並行查詢進程個數.
Cache 用來指定該表為最應該緩存在SGA數據庫緩沖池中的候選項.
Cluster 用來指定該表所存儲的 cluster.
Tablespace 用來指定用數據庫的那個分區來存儲該表的數據.
Recoverable|Unrecoverable 用來決定是否把對本表數據所作的變動寫入Redo 文件.以恢復對數據的操作.
As 當不指定表的各列時,可利用As子句的查詢結果來產生數據庫結構和數據.
例:
1) create table mytab1e(mydec decimal,
myint inteter)
tablespace user_data
pctfree 5
pctused 30;
2) create table mytable2
as ( select * from mytable1);
二、
create sequence語句
語句: CREATE SEQUENCE [schema.]sequence_name
[INCREMENT BY integer]
[START WITH integer]
[MAXVALUE integer | NOMAXVALUE]
[MINVALUE integer | NOMINVALUE]
[CYCLE | NOCYCLE]
[CACHE integer | NOCACHE]
[ORDER | NOORDER]
序列用來為表的主鍵生成唯一的序列值.
Increment by 指定序列值每次增長的值
Start with 指定序列的第一個值
Maxvalue 指定產生的序列的最大值
Minvalue 指定產生的序列的最小值
Cycle 指定當序列值逵到最大或最小值時,該序列是否循環.
Cache 指定序列生成器一次緩存的值的個數
Order 指定序列中的數值是否按訪問順序排序.
例:
1) create sequence myseq
increment by 4
start with 50
maxvalue 60
minvalue 50
cycle
cache 3;
2)
sql> create sequence new_s;
sql>insert into new (new_id,last_name,first_name)
values(new_s.nextval,’daur’,’permit’);
三、
create view語句
語句: CREATE [OR REPLACE] [FORCE | NOFORCE] VIEW [schema.]view_name
[(alias [,alias]...)]
AS subquery
[WITH CHECK OPTION [CONSTRAINT constraint]]
視圖實際上是存儲在數據庫上旳 select語句.每次在sql語句中使用視圖時,表示該視圖的select語句就用來得到需要的數據.
Or replace 創建視圖時如果視圖已存在,有此選項,新視圖會覆蓋舊的
視圖.
Force 如有此選項,當視圖基於的表不存在或在該模式中沒有創建視圖的權限時,也可以建立視圖.
As subquery 產生視圖的select查詢語句
With check option 如果視圖是基於單表的且表中所有的非空列都包含在視圖中時,該視圖可用於insert和update語句中,本 選項保證在每次插入或更新數據后,該數據可以在視 圖中查到
例:
1) create or place view new_v
as
select substr(d.d_last_name,1,3),
d.d_lastname,d.d_firstname,b.b_start_date,b.b_location
from new1 d,
new2 b
where d.d_lastname=b.b_lastname;
四、
INSERT語句:
1. 語法
INSERT INTO [schema.]{table | view | subquery }[@dblink]
[ (column [, column] ...) ]
{VALUES (expr [, expr] ...) | subquery}
[WHERE condition]
2. 插入單行
使用VALUES關鍵詞為新行的每一列指定一個值.如果不知道某列的值,可以使用NULL關鍵詞將其值設為空值(兩個連續的逗號也可以表示空值,也可使用NULL關鍵詞)
插入一行時試圖為那些NOT NULL的列提供一個NULL值,會返回錯誤信息.
舉例:
插入一條記錄到DEPARTMENT表中
INSERT INTO DEPARTMENT
(DEPARTMENT_ID,NAME,LOCATION_ID)
VALUES (01,’COMPUTER’,167)
3. 插入多行
將SELECT語句檢索出來的所有數據行都插入到表中.這條語句通常在從一個表向另一個表快速復制數據行.
舉例:
INSERT INTO ORDER_TEMP
SELECT A.ORDER_ID,B.ITEM_ID,C.NAME,E.FIRST_NAME||'.'||E.LAST_NAME,
A.ORDER_DATE,A.SHIP_DATE,D.DESCRIPTION,B.ACTUAL_PRICE,
B.QUANTITY,B.TOTAL
FROM SALES_ORDER A, ITEM B, CUSTOMER C,
PRODUCT D, EMPLOYEE E
WHERE MONTHS_BETWEEN(TO_DATE(A.ORDER_DATE),TO_DATE('01-7月-91'))>0
AND A.CUSTOMER_ID=C.CUSTOMER_ID
AND C.SALESPERSON_ID=E.EMPLOYEE_ID
AND A.ORDER_ID=B.ORDER_ID
AND B.PRODUCT_ID=D.PRODUCT_ID
4. 從其它表復制數據:
要快速地從一個表向另一個尚不存在的表復制數據,可以使用CREATE TABLE語句定義該表並同時將SELECT語句檢索的結果復制到新表中.
CREATE TABLE EMPLOYEE_COPY
AS
SELECT *
FROM EMPLOYEE
五、
UPDATE語句:
1. 語法
UPDATE [schema.]{table | view | subquery}[@dblink] [alias]
SET { (column [, column] ...) = (subquery)
| column = { expr | (subquery) } }
[, { (column [, column] ...) = (subquery)
| column = { expr | (subquery) } } ] ...
[WHERE condition]
UPDATE語句更新所有滿足WHERE子句條件的數據行.同樣,該語句可以用SELECT語句檢索得到.但SELECT必須只檢索到一行數據值.否則報錯.而且每更新一行數據,均要執行一次SELECT語句.
舉例:
UPDATE EMPLOYEE_COP
SET SALARY=
SALARY-400
WHERE TO_NUMBER(TO_CHAR(HIRE_DATE,'YYMMDD'))<850101
UPDATE ITEM_COP A
SET A.ACTUAL_PRICE=
(
SELECT B.LIST_PRICE
FROM PRICE B,SALES_ORDER C
WHERE A.PRODUCT_ID=B.PRODUCT_ID AND
A.ORDER_ID=C.ORDER_ID AND
TO_NUMBER(TO_CHAR(C.ORDER_DATE,'YYYYMMDD')) BETWEEN
TO_NUMBER(TO_CHAR(B.START_DATE,'YYYYMMDD')) AND
NVL(TO_NUMBER(TO_CHAR(END_DATE,'YYYYMMDD')),29991231)
)
六、
DELETE語句:
1. 語法
DELETE [FROM] [schema.]{table | view}[@dblink] [alias]
[WHERE condition]
DELETE語句刪除所有滿足WHERE子句條件的數據行.
舉例:
DELETE FROM item
WHERE ORDER_ID=510
七、
TRUNCATE語句:
1. 語法
TRUNCATE [schema.]table
八、
各類Functions:
1. 轉換函數:
1.1. 函數:TO_CHAR
語法:
TO_CHAR(number[,format])
用途:
將一個數值轉換成與之等價的字符串.如果不指定格式,將轉換成最簡單的字符串形式.如果為負數就在前面加一個減號.
Oracle為數值提供了很多格式,下表列出了部分可接受的格式:
元素 |
描述 |
示例 |
值 |
結果 |
9 |
返回指定位數的數值,前面為0,顯示為空格 |
99999 |
784 -578 1234567 45.895 |
‘ 784’ ‘ -578’ ‘######’ ‘ 46’ |
插入小數點 |
9999.99 |
784 45.3482 |
‘784.00’ ’45.35’ |
|
在結果串的指定位置插入逗號 |
9,999,999 |
784 1234567 0.44 |
‘ 784’ ‘ 1,234,567’ ‘ 0’ |
|
$ |
返回值前面加一個元符號 |
$99,999 |
784 -578 |
‘ $784’ ‘ -$578’ |
B |
結果的整數部分如果是0,就顯示成空格 |
B9999.9 |
784 0.44 |
‘ 784.0’ ‘ .4’ |
S |
返回 有正負號的數值 |
S9999 |
784 |
‘+784’ |
EEEE |
以科 計數法表示數值 |
9.9EEEE |
45 0.0666 |
‘ 4.5E+01’ ‘ 6.7E-02’ |
1.2.
函數:TO_CHAR
語法:
TO_CHAR(date[,format])
用途:
將按format參數指定的格式將日期值轉換成相應的字符串形式.同樣,Oracle提供許多的格式模型,用戶可以用它們的組合來表示最終的輸出格式.唯一限制就是最終的掩碼不能超過22個字符.下表列出了部分日期格式化元素.
Oracle為數值提供了很多格式,下表列出了部分可接受的格式:
格式 |
意義 |
D |
用數字表示星期幾(1,2,3,4,5,6,7) |
DY |
用三個字符表示星期幾的縮寫形式(MON) |
DAY |
星期幾的完整表示(MONDAY) |
DD |
用數字表示一月中的幾號 |
DDD |
用數字表示年份中的天數 |
W |
一月中的星期數 |
WW |
一年中的星期數 |
MM |
用數字表示月數 |
MON |
用三個字母表示月的縮寫(APR) |
MONTH |
月的完整英文表示(FEBRUARY) |
Y |
年份中的最后一個數字(9) |
YY |
年份中的最后二個數字(99) |
YYY |
年份中的最后三個數字(999) |
YYYY |
年份用四個數字表示(1999) |
YEAR |
年份的字母全部拼寫(NINETEEN-NINETY-NINE) |
AM或PM |
午前或午后表示符 |
HH |
用小時表示日期 |
MI |
分鍾表示小時 |
SS |
秒鍾表示分鍾 |
SSSS |
自午夜以來的秒數(這個數字經常在0-86399之間) |
1.3.
函數:TO_DATE
語法:
TO_DATE(string,format)
用途:
根據給定的格式將一個字符串轉換成Oracle的日期值.
該函數的主要用途是用來驗證輸入的日期值.在應用程序中,用戶必須驗證輸入日期是否有效,如月份是否在1~12之間和日期中的天數是否在指定月份的天數內.
1.4.
函數:TO_NUMBER
語法:
TO_NUMBER(string[,format])
用途:
該函數將一個字符串轉換成相應的數值.對於簡單的字符串轉換數值(例如幾位數字加上小數點).格式是可選的.
2.
日期函數
2.1. 函數:ADD_MONTHS
語法:
ADD_MONTHS(date,number)
用途:
在日期date上加指定的月數,返回一個新日期.如果給定為負數,返回值為日期date之前幾個月的日期.number應當是個整數,如果是小數,正數被截為小於該數的最大整數,負數被截為大於該數的最小整數.
例如:
SELECT TO_CHAR(ADD_MONTHS(sysdate,1),
'DD-MON-YYYY') "Next month"
FROM dual
Next month
-----------
19-FEB-2000
2.2. 函數:LAST_DAY
語法:
LAST_DAY(date)
用途:
返回日期date所在月份的最后一天的日期.
例如:
SELECT SYSDATE, LAST_DAY(SYSDATE) "Last",
LAST_DAY(SYSDATE) - SYSDATE "Days Left"
FROM DUAL
SYSDATE Last Days Left
--------- --------- ----------
19-JAN-00 31-JAN-00 12
2.3. 函數:MONTHS_BETWEEN
語法:
MONTHS_BETWEEN(date1,date2)
用途:
返回兩個日期之間的月份.如果兩個日期月份內的天數相同(或者都是某個月的最后一天),返回值是整數.否則,返回值是小數,每於1/31月來計算月中剩余天數.如果第二個日期比第一個日期還早,則返回值是負數.
例如:
SELECT MONTHS_BETWEEN(TO_DATE('02-02-1992', 'MM-DD-YYYY'),
TO_DATE('01-01-1992', 'MM-DD-YYYY'))
"Months"
FROM DUAL
Months
----------
1.03225806
SELECT MONTHS_BETWEEN(TO_DATE('02-29-1992', 'MM-DD-YYYY'),
TO_DATE('01-31-1992', 'MM-DD-YYYY'))
"Months"
FROM DUAL
Months
----------
1
2.4. 函數:NEXT_DAY
語法:
NEXT_DAY(date,day)
用途:
該函數返回日期date指定若天后的日期.注意:參數day必須為星期,可以星期幾的英文完整拼寫,或前三個字母縮寫,或數字1,2,3,4,5,6,7分別表示星期日到星期六.例如,查詢返回本月最后一個星期五的日期.
例如:
SELECT NEXT_DAY((last_day(sysdate)-7),'FRIDAY')
FROM dual
NEXT_DAY(
---------
28-JAN-00
2.5. 函數:ROUND
語法:
NEXT_DAY(date[,format])
用途:
該函數把一個日期四舍五入到最接近格式元素指定的形式.如果省略format,只返回date的日期部分.例如,如果想把時間(24/01/00 14:58:41)四舍五入到最近的小時.下表顯示了所有可用格式元素對日期的影響.
Format Element |
Result |
SS |
24/01/00 14:58:41 |
MI |
24/01/00 14:59:00 |
HH |
24/01/00 15:00:00 |
DD |
25/01/00 00:00:00 |
MM |
01/02/01 00:00:00 |
YY |
01/01/00 00:00:00 |
CC |
01/01/00 00:00:00 |
例如:
SELECT to_char(ROUND(sysdate,'HH'),'DD-MON-YY HH24:MI:SS')
FROM dual
TO_CHAR(ROUND(SYSDATE,'HH'),'DD-MON-YYHH24:MI:SS')
-----------------------------------------------------------------
24-JAN-00 15:00:00
2.6. 函數:TRUNC
語法:
TRUNC(date[,format])
用途:
TRUNC函數與ROUND很相似,它根據指定的格式掩碼元素,只返回輸入日期用戶所關心的那部分,與ROUND有所不同,它刪除更精確的時間部分,而不是將其四舍五入.
例如:
SELECT TRUNC(sysdate)
FROM dual
TRUNC(SYS
---------
24-JAN-00
FLOOR函數:求兩個日期之間的天數用;
select floor(sysdate - to_date('20080805','yyyymmdd')) from dual;
3.
字符函數
3.1. 函數:ASCII
語法:
ASCII(character)
用途:
返回指定字符的ASCII碼值.如果為字符串時,返回第一個字符的ASCII碼值.
例如:
SELECT ASCII('Z')
FROM dual
ASCII('Z')
----------
90
3.2. 函數:CHR
語法:
CHR(number)
用途:
該函數執行ASCII函數的反操作,返回其ASCII碼值等於數值number的字符.該函數通常用於向字符串中添加不可打印字符.
例如:
SELECT CHR(65)||'BCDEF'
FROM dual
CHR(65
------
ABCDEF
3.3.
函數:CONCAT
語法:
CONCAT(string1,string2)
用途:
該函數用於連接兩個字符串,將string2跟在string1后面返回,它等價於連接操作符(||).
例如:
SELECT CONCAT(‘This is a’,’ computer’)
FROM dual
CONCAT('THISISA','
------------------
This is a computer
它也可以寫成這樣:
SELECT ‘This is a’||’ computer’
FROM dual
'THISISA'||'COMPUT
------------------
This is a computer
這兩個語句的結果是完全相同的,但應盡可能地使用||操作符.
3.4. 函數:INITCAP
語法:
INITCAP(string)
用途:
該函數將字符串string中每個單詞的第1個字母變成大寫字母,其它字符為小寫字母.
例如:
SELECT INITCAP(first_name||'.'||last_name)
FROM employee
WHERE department_id=12
INITCAP(FIRST_NAME||'.'||LAST_N
-------------------------------
Chris.Alberts
Matthew.Fisher
Grace.Roberts
Michael.Douglas
3.5. 函數:INSTR
語法:
INSTR(input_string,search_string[,n[,m]])
用途:
該函數是從字符串input_string的第n個字符開始查找搜索字符串的第m次出現,如果沒有找到搜索的字符串,函數將返回0.如果找到,函數將返回位置.
例如:
SELECT INSTR('the quick sly fox jumped over the
lazy brown dog','the',2,1)
FROM dual
INSTR('THEQUICKSLYFOXJUMPEDOVERTHELAZYBROWNDOG','THE',2,1)
----------------------------------------------------------
31
3.6. 函數:INSTRB
語法:
INSTRB(input_string,search_string[,n[,m]])
用途:
該函數類似於INSTR函數,不同之處在於INSTRB函數返回搜索字符串出現的字節數,而不是字符數.在NLS字符集中僅包含單字符時,INSTRB函數和INSTR函數是完全相同的.
3.7. 函數:LENGTH
語法:
LENGTH(string)
用途:
該函數用於返回輸入字符串的字符數.返回的長度並非字段所定義的長度,而只是字段中占滿字符的部分.以列實例中,字段first_name定義為varchar2(15).
語法:
SELECT first_name,LENGTH(first_name)
FROM employee
FIRST_NAME LENGTH(FIRST_NAME)
--------------- ------------------
JOHN 4
KEVIN 5
3.8. 函數:LENGTHB
語法:
LENGTHB(string)
用途:
該函數用於返回輸入字符串的字節數.對於只包含單字節字符的字符集來說LENGTHB函數和LENGTH函數完全一樣.
3.9. 函數:LOWER
語法:
LOWER(string)
用途:
該函數將字符串string全部轉換為小寫字母,對於數字和其它非字母字符,不執行任何轉換.
3.10. 函數:UPPER
語法:
UPPER(string)
用途:
該函數將字符串string全部轉換為大寫字母,對於數字和其它非字母字符,不執行任何轉換.
3.11. 函數:LPAD
語法:
LPAD(string,length[,’set’])
用途:
在字符串string的左邊加上一個指定的字符集set,從而使串的長度達到指定的長度length.參數set可以是單個字符,也可以是字符串.如果string的長度小於length時,取string字符串的前length個字符.
語法:
SELECT first_name,LPAD(first_name,20,' ')
FROM employee
FIRST_NAME LPAD(FIRST_NAME,20,'')
--------------- -----------------------------------------
JOHN JOHN
KEVIN KEVIN
3.12. 函數:RPAD
語法:
RPAD(string,length[,’set’])
用途:
在字符串string的右邊加上一個指定的字符集set,從而使串的長度達到指定的長度length.參數set可以是單個字符,也可以是字符串.如果string的長度小於length時,取string字符串的前length個字符.
例如:
SELECT first_name,rpad(first_name,20,'-')
FROM employee
FIRST_NAME RPAD(FIRST_NAME,20,'-')
--------------- -----------------------------------------
JOHN JOHN----------------
KEVIN KEVIN---------------
3.13. 函數:LTRIM
語法:
LTRIM(string[,’set’])
用途:
該函數從字符串的左邊開始,去掉字符串set中的字符,直到看到第一個不在字符串set中的字符為止.
例如:
SELECT first_name,ltrim(first_name,'BA')
FROM employee
WHERE first_name='BARBARA'
FIRST_NAME LTRIM(FIRST_NAM
--------------- ---------------
BARBARA RBARA
3.14. 函數:RTRIM
語法:
RTRIM(string[,’set’])
用途:
該函數從字符串的右邊開始,去掉字符串set中的字符,直到看到第一個不在字符串set中的字符為止.具有NULL值的字段不能與具有空白字符的字段相比較.
這是因為空白字符與NULL字符是完全不同的兩種字符.該函數的另外一個用途是當進行字段連接時去掉不需要的字符.
3.15. 函數:SUBSTR
語法:
SUBSTR(string,start[,length])
用途:
該函數從輸入字符串中取出一個子串,從start字符處開始取指定長度的字符串,如果不指定長度,返回從start字符處開始至字符串的末尾.
3.16. 函數:REPLACE
語法:
REPLACE(string,search_set[,replace_set])
用途:
該函數將字符串中所有出現的search_set都替換成replace_set字符串.可以使用該函將字符串中所有出現的符號都替換成某個有效的名字.如果不指定replace_set,則將從字符串string中刪除所有的搜索字符串search_set.
例如:
SELECT REPLACE('abcdefbdcdabc,dsssdcdrd','abc','ABC')
FROM dual
REPLACE('ABCDEFBDCDABC,
-----------------------
ABCdefbdcdABC,dsssdcdrd
3.17. 函數:TRANSLATE
語法:
TRANSLATE(string,search_set,replace_set)
用途:
該函數用於將所有出現在搜索字符集search_set中的字符轉換成替換字符集replace_set中的相應字符.注意:如果字符串string中的某個字符沒有出現在搜索字符集中.則它將原封不動地返回.如果替換字符集replace_set比搜索字符集search_set小,那么搜索字符集search_set中后面的字符串將從字符串string中刪除.
例如:
SELECT TRANSLATE('GYK-87M','0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
9999999999xxxxxxxxxxxxxx')
FROM dual
TRANSL
------
xx-99x
4.
數值函數
4.1. 函數:ABS
語法:
ABS(number)
用途:
該函數返回數值number的絕對值.絕對值就是一個數去掉符號的那部分.
4.2. 函數:SQRT
語法:
SQRT(number)
用途:
該函數返回數值number的平方根,輸入值必須大於等於0,否則返回錯誤.
4.3. 函數:CEIL
語法:
CEIL(number)
用途:
該函數返回大於等於輸入值的下一個整數.
4.4. 函數:FLOOR
語法:
FLOOR(number)
用途:
該函數返回小於等於number的最大整數.
4.5.
函數:MOD
語法:
MOD(n,m)
用途:
該函數返回n除m的模,結果是n除m的剩余部分.m,n可以是小數,負數.
4.6. 函數:POWER
語法:
POWER(x,y)
用途:
該函數執行LOG函數的反操作,返回x的y次方.
4.7. 函數:ROUND
語法:
ROUND(number,decimal_digits)
用途:
該函數將數值number四舍五入到指定的小數位.如果decimal_digits為0,則返回整數.decimal_digits可以為負數.
4.8. 函數:TRUNC
語法:
TRUNC(number[,decimal_pluces])
用途:
該函數在指定的小數字上把一個數值截掉.如果不指定精度,函數預設精度為0. decimal_pluces可以為負數.
4.9.
函數:SIGN
語法:
SIGN(number)
用途:
該函數返回number的符號,如果number為正數則返回1,為負數則返回-1,為0則返回0.
4.10. 函數:SIN
語法:
SIN(number)
用途:
該函數返回弧度number的正弦值.
4.11. 函數:SINH
語法:
SINH(number)
用途:
該函數返回number的返正弦值.
4.12. 函數:COS
語法:
COS(number)
用途:
該函數返回弧度number的三角余弦值.要用角度計算余弦,可以將輸入值乘以0.01745轉換成弧度后再計算.
4.13.
函數:COSH
語法:
COSH(number)
用途:
該函數返回輸入值的反余弦值.
4.14. 函數:TAN
語法:
TAN(number)
用途:
該函數返回弧度number的正切值.
4.15. 函數:TANH
語法:
TANH(number)
用途:
該函數返回數值number的反正切值.
4.16. 函數:LN
語法:
LN(number)
用途:
該函數返回number自然對數.
4.17.
函數:EXP
語法:
EXP(number)
用途:
該函數返回e(2.71828183)的number次方.該函數執行自然對數的反過程.
4.18. 函數:LOG
語法:
LOG(base,number)
用途:
該函數返回base為底,輸入值number的對數.
5.
單行函數:
單行函數中可以對任何數據類型的數據進行操作.
5.1. 函數:DUMP
語法:
DUMP(expression[,format[,start[,length]]])
用途:
該函數按指定的格式顯示輸入數據的內部表示.下表列出了有效的格式.
格式代碼 |
描述 |
8 |
八進制 |
10 |
十進制 |
16 |
十六進制 |
17 |
單字符 |
例如:
SELECT DUMP('FARRELL',16)
FROM dual
DUMP('FARRELL',16)
----------------------------------
Typ=96 Len=7: 46,41,52,52,45,4c,4c
5.2. 函數:GREATEST
語法:
GREATEST(list of values)
用途:
該函數返回列表中項的最大值.對數值或日期來說,返回值是最大值或最晚日期,如果列表中包含字符串,返回值是按字母順序列表中的最后一項.
例如:
SELECT GREATEST(123,234,432,112)
FROM dual
GREATEST(123,234,432,112)
-------------------------
432
5.3. 函數:LEAST
語法:
LEAST(list of values)
用途:
該函數返回列表中項的最小值.對數值或日期來說,返回值是最小值或最早日期,如果列表中包含字符串,返回值是按字母順序列表中的第一項.
例如:
SELECT LEAST(sysdate,sysdate-10)
FROM dual
LEAST(SYS
---------
10-JAN-00
5.4. 函數:NVL
語法:
NVL(expression,replacement_value)
用途:
如果表達式不為空值,函數返回該表達式的值,如果是空值,就返回用來替換的值.
例如:
SELECT last_name,
NVL(TO_CHAR(COMMISSION),'NOT APPLICABLE')
FROM employee
WHERE department_id=30
LAST_NAME NVL(TO_CHAR(COMMISSION),'NOTAPPLICABLE')
--------------- ----------------------------------------
ALLEN 300
WARD 500
MARTIN 1400
BLAKE NOT APPLICABLE
6.
多行函數
組函數可以對表達式的所有值操作,也可以只對其中不同值進行操作,組函數的語法如下所示:
function[DISTINCT|ALL expression]
如果既不指定DISTINCT,也不指定ALL,函數將對查詢返回的所有數據行進行操作.不能在同一個SELECT語句的選擇列中同時使用組函數和單行函數.
6.1. 函數:AVG
語法:
AVG([DISTINCT|ALL] expression)
用途:
對查詢返回的數據行求平均值.
例如:
SELECT AVG(sal) "Average"
FROM emp
Average
----------
2073.21429
6.2. 函數:COUNT
語法:
COUNT([DISTINCT|ALL] expression)
用途:
計算表達式的個數.要計算EMP表中雇員的個數.
例如:
SELECT COUNT(deptno)
FROM emp
COUNT(DEPTNO)
-------------
14
SELECT COUNT(distinct deptno)
FROM emp
COUNT(DISTINCTDEPTNO)
---------------------
3
6.3. 函數:MAX
語法:
MAX([DISTINCT|ALL] expression)
用途:
對查詢返回的行集求最大值.如果有多個最大值,將所有均返回.要檢索公司中最高工資的雇員.
語法:
SELECT ename,sal
FROM emp
WHERE sal=(select max(sal)
FROM emp)
ENAME SAL
---------- ---------
KING 5000
6.4. 函數:MIN
語法:
MIN([DISTINCT|ALL] expression)
用途:
對查詢返回的行集求最小值.如果有多個最小值,將所有均返回.
例如:
SELECT MIN(last_name)
FROM employee
MIN(LAST_NAME)
---------------
ADAMS
6.5. 函數:SUM
語法:
SUM([DISTINCT|ALL] expression)
用途:
計算查詢返回的所有非空數值的總和.如果返回的數據都是空值,則該函數也返回空值.
例如:
SELECT SUM(salary)"Total"
FROM employee
WHERE department_id=10
Total
---------
8750
6.6. 函數:VARIANCE
語法:
VARIANCE([DISTINCT|ALL] expression)
用途:
該函數計算返回所有行的統計方差.
例如:
SELECT VARIANCE(salary)
FROM employee
VARIANCE(SALARY)
----------------
973659.27
偽列 |
返回值 |
Sequence.CURRVAL |
上一次由序列產生器產生的序列名值.只有在當前實例會話中從該序列選擇過一次值,這個偽列才會有效. |
LEVEL |
查詣的深度,LEVEL適用於特殊的樹查詢. |
Sequence.NEXTVAL |
選擇這個偽列將導致序列發生器返回該序列的下一個值.一旦選擇了該值,它就不能被重用,因為以后的每次檢索都將返回下一個值. |
ROWID |
這個偽列表示數據行確切的存儲位置.ROWID的格式是一個三個16進制數的結構AAAAAAAA.BBBB.CCCC,這里AAAAAAAA表示數據庫文件中包含該行的塊號,BBBB是數據塊內部的行號,而CCCC則是數據中的文件ID. |
ROWNUM |
被檢索數據行的序列號. |
SYSDATE |
當前日期和時間. |
UID |
當前用戶的標識ID. |
USER |
用戶登錄進數據庫的名字. |
TABLE: LOCATION 部門地址表
-------------------- -------- ----
LOCATION_ID NOT NULL NUMBER(3) 地址ID
REGIONAL_GROUP VARCHAR2(20) 地址名
TABLE: DEPARTMENT 部門名稱表
-------------------- -------- ----
DEPARTMENT_ID NOT NULL NUMBER(2) 部門ID
NAME VARCHAR2(14) 部門名稱
LOCATION_ID NUMBER(3) 地址ID(LOCATION.LOCATION_ID)
TABLE: JOB 工種表
-------------------- -------- ----
JOB_ID NOT NULL NUMBER(3) 工種ID
FUNCTION VARCHAR2(30) 工種名稱
TABLE: EMPLOYEE 雇員信息表
-------------------- -------- ----
EMPLOYEE_ID NOT NULL NUMBER(4) 雇員ID
LAST_NAME VARCHAR2(15)
FIRST_NAME VARCHAR2(15)
MIDDLE_INITIAL VARCHAR2(1)
JOB_ID NUMBER(3) 工種ID(JOB.JOB_ID)
MANAGER_ID NUMBER(4) 領導ID(EMPLOYEE.EMPLOYEE_ID)
HIRE_DATE DATE 雇佣日期
SALARY NUMBER(7,2) 薪水
COMMISSION NUMBER(7,2) 佣金
DEPARTMENT_ID NUMBER(2) 部門ID(DEPARTMENT.DEPARTMENT_ID)
TABLE: SALARY_GRADE 薪資等級表
-------------------- -------- ----
GRADE_ID NOT NULL NUMBER(3) 等級ID
LOWER_BOUND NUMBER(7,2) 最低工資
UPPER_BOUND NUMBER(7,2) 最高工資
TABLE: PRODUCT 產品信息表
-------------------- -------- ----
PRODUCT_ID NOT NULL NUMBER(6) 品號
DESCRIPTION VARCHAR2(30) 品名
TABLE: PRICE 產品價格表
-------------------- -------- ----
PRODUCT_ID NOT NULL NUMBER(6) 品號(PRODUCT.PRODUCT_ID)
LIST_PRICE NUMBER(8,2) 價格
MIN_PRICE NUMBER(8,2) 最低價格
START_DATE NOT NULL DATE 生效日期
END_DATE DATE 失效日期
TABLE: CUSTOMER 客戶信息表
-------------------- -------- ----
CUSTOMER_ID NOT NULL NUMBER(6) 客戶ID(CUSTOMER.CUSTOMER_ID)
NAME VARCHAR2(45) 客戶名
ADDRESS VARCHAR2(40) 客戶地址
CITY VARCHAR2(30) 城市
STATE VARCHAR2(2) 州
ZIP_CODE VARCHAR2(9) 郵編
AREA_CODE NUMBER(3) 區號
PHONE_NUMBER NUMBER(7) 電話號碼
SALESPERSON_ID NUMBER(4) 銷售員ID(EMPLOYEE.EMPLOYEE_ID)
CREDIT_LIMIT NUMBER(9,2) 信用限制
COMMENTS LONG 備注
TABLE: SALES_ORDER 訂單單頭表
-------------------- -------- ----
ORDER_ID NOT NULL NUMBER(4) 訂單ID
ORDER_DATE DATE 訂單日期
CUSTOMER_ID NUMBER(6) 客戶ID(CUSTOMER.CUSTOMER_ID)
SHIP_DATE DATE 出貨日期
TOTAL NUMBER(8,2) 總金額
TABLE: ITEM 訂單單身表
-------------------- -------- ----
ORDER_ID NOT NULL NUMBER(4) 訂單ID(SALES_ORDER.ORDER_ID)
ITEM_ID NOT NULL NUMBER(4) 訂單行號
PRODUCT_ID NUMBER(6) 品號(PRODUCT.PRODUCT_ID)
ACTUAL_PRICE NUMBER(8,2) 實際價格
QUANTITY NUMBER(8) 訂單數量
TOTAL NUMBER(8,2) 總金額
第二部分 PL/SQL語法部分
一、 PL/SQL語言簡介
(本講義之所有程序均調式通過)
首先我們看一個簡單之例子,下面這個例子是統計從1至100的總和.
declare
i number:=0; /*聲明變量井給初值*/
t number:=1;
error_message exception; /*聲明一個出錯處理*/
begin
for t in 1..100 loop
i:=i+t;
end loop;
if i>=5050 then
raise error_message; /*引發錯誤處理*/
else
insert into c_nt(c_t) values(i);
end if;
exception
when error_message then
insert into c_nt(c_t) values(0);
end;
² 從上例中可以看出PL/SQL語法的一般規則.
PL/SQL中語句以分號(;)結尾.
開始程序塊的PL/SQL語句(如IF…或BEGIN語句)沒有分句.
文本值括在單引號(‘ ‘)內,而不是(“ “).
過程只允許最后有一個出口..
² PL/SQL程序可以分為三個部分
DECLARE部分用於變量、常量、函數、過程、Cursor.
BEGIN部分包含PL/SQL塊中要執行的代碼 用於程序處理,其中可以調用函數、過程.
Exception 部分用於出錯處理.
下面我們再看一個例子:
declare
i number :=1;
t number :=1;
p number :=1;
/*create table c_ny(c_t number,cou_t number);*/
function aa(xx number)return number is /* define function*/
tt number;
ct number:=1;
j number:=1;
begin
while j<=xx loop
ct:=ct+j;
j:=j+1;
end loop;
return ct;
end aa;
begin
/*create table c_nt(c_t number,cou_t number);*/
commit;
while i<=200 loop
t:=t+i;
i:=i+1;
p:=aa(i); /* calling function*/
insert into c_nt values(t,p);
commit;
end loop;
end;
/
說明:
1.在定義變量可以賦初值,賦初值有兩種方法,一為上程序所示,另一種為如下所示:
Declare
I number default 92;
T number default 0;
2.定義常量
Declare
I constant number:=1;
T constant number:=9;
3.定義函數
function function_name(parameter type)return type is
…declare variant
begin
…
…
end function_name;
在上面的例子中我們定義了一個函數aa,在begin模塊部分引用了此函數aa().
4.定義過程
procedure procedure_name(parameter IN type) is
…declare variant
begin
…
…
exception
…
…
end procedure_name;
見下例:
declare
/*t_emp c_nt%rowtype;*/
i number:=1;
t number:=1;
procedure te_t(t_t number) is /*定義一個函數*/
begin
insert into c_nt1(t_1) values(t_t);
end te_t;
begin
for i in 1..100 loop
te_t(i);
end loop;
end;
/
5.定義Cursor
declare
/*t_emp c_nt%rowtype;*/
t_emp1 number;
t_emp2 number;
cursor tes_t1
is select * from c_nt;
begin
open tes_t1;
delete from c_nt1;
commit;
loop
fetch tes_t1 into t_emp1,t_emp2;
exit when tes_t1%notfound;
insert into c_nt1 values(t_emp1,t_emp2);a
end loop;
close tes_t1;
commit;
end;
/
我們在open 一個cursor時,可能會存在一種情況,即我們不需要cursor中所有之記錄,我們該如何處理:
1.在定義一個cursor時,可以附帶參數如下所示
declae
cursor c1(p_emp_id) is
select emp_no,emp_name from dept_no where emp_id = p_emp_id;
demp_pt c1%rowtype;
…
…
begin
open c1(123);
loop
fetch c1(123) into demp_pt
…
2.在將cursor中之記錄項轉到變量中時進行控制,如下所示:
declare
cursor is
select empt_no,empt_name from dept_no;
p_no number;
p_name number;
begin
loop
fetch c1 into (p_no,p_name);
if condition1 then
…
…
end if
end;
注意:
² 因為PL/SQL不支持I/O,所以程序所有結果都是放在數據檔中.
² Delete from accts where status=’bad debt’
If sql%rowcount>10 then
Raise out_of_bounds;
End if;
另:
在聲明一個變量時,PL/SQL提供兩種變量類型:%TYPE,%ROWTYPE.
1.%TYPE
使用%TYPE時,可以有種用法:
² 一用法見下例:
declare
Balance number(7,2);
Minimum_balance balance%type:=10.00;
在上例中,minimum_balance數據類型為number(7,2)具默認值為10.00.
² 二用法見下例(將數據類型與table中一column datatype相對應起來,如果table中column datatype變更,則在運行時,上數據類型會自動的變換上):
declare
my_dname empc.empto%type;
2.%rowtype
使用%rowtype數據類型用於將table和cursor中一數據行相對起來.
見下例:
² Declare
Cursor my_cursor is select sal+nvl(comm,0) salcomm,wages,ename from emp;
My_rec my_cursor%rowtype;
Begin
Open my_cursor;
loop
Fetch my_cursor into my_rec ;
Exit when my_cursor%notfound;
If my_rec.wages>200 then
Insert into temp values (null,my_rec.wages,my_rec.ename);
End if;
End loop;
Close my_cursor;
End;
二、
變量說明
在PL/SQL中包括以下幾種常見的變量類型:
CHAR-存儲定長的ASCII字符串,允許存儲數字,文本文符等,最長可255個字符.
VARCHAR2-存儲變長的字符串,盡管伋按符串的最大長度來定義,但VARCHAR2和CHAR的區別在於如果達不到定義的長度,下的空間不會自動的填寫為空格,VARCHAR2最大可以放入2000個字符.
DATE-實際上是存儲時間信息的日期/時間戳,在使用日期時,應考慮怎樣使用日期函數.有關日期函數的格式見函數說明部分.
NUMBER-存儲數值數據,包括整數和浮點數、數據范圍可以從1Ï10 到38Ï10 ,而且,你有很大的數據空間.
BOOLENA-存儲布爾值.它表示是/否,真/假,1/0之類的東西.
LONG-這是一種文本字符串,其長度大於VARCHAR2字段的2000個字符.該類最多可儲存2 GB個字符,與原始二進制數據相比,它只能存儲字符信息.
RAW-用來存儲操作系統使用的原始二進制數據,可用於存儲像圖像或聲音記錄這樣的信息,但這種數據長度最長度只有255字節.
LONG RAW-與LONG類型等價,但存儲二進制數據,最長可達2GB個字節.
BINARY_INTEGER-這個字段按計算器使用的二進制格式存儲信息,從
-2 到2 -1.
另:
PL/SQL提位兩種復合類型:TABLE和RECORD
1.TABLE
² 要定義一個數組,你使用表類型定義語句,例如要定義Last_name數組,可以使用下述語句:
type last_name_list is table of varchar2(22)
index by binary_integer;
last_name last_name_list;
² 當定義一個長類型時,就涉及到一個刪除表的問題,PL/SQL表不能用Delete語句來刪除,但可以將每一行空值如下所示:
sal_tab(3):=null;
另一種法是定義兩個相同類型的表類型,如果要將另一表清空,只需將空表給要清空的表即可.如下所示.
declare
type numtabtype is table of number
index by binary_integer;
sal_tab numbertype;
empty_tab numbertype;
begin
for I in 1..100 loop
sal_tab(I):=I;
end loop;
….
End;
2.RECORD
Declare
Type deptrectype is record
(deptno number(2),
dname char(14),
loc char(14),);
dept_rec deptrectype;
begin
select deptno,dname,loc into dept_rec from dept where deptno=30;
…
…
end;
與所有的編程語言一樣,定義一個變量時,同樣存在變量作用范圍問題:
如下所示:
declare
x real;
function function_name(variant type)return type is
declare
x char;
begin
…
end function_name;
…
…
begin
x:=expression1…
…
end;
如果想引用另一block之變量時,可以加上block label,如下所示:
<<outer>>
declare
birthdate date;
begin
…
declare
birthdate date;
begin
….
If birthdate=outer.birthdate then
….
End if;
End;
End outer;
三、
PL/SQL控制程序流
1. IF …THEN…ELSIF…ELSE…….END IF
IF … THEN
STATMENT1;
elseif…then…
statment2
elseif…then…
statment3
ELSE
STATMENT4;
end if;
例:
<<outer>>
for ctr in 1..20 loop
…
<<inner>>
for ctr in 1..10 loop
if outer.ctr>ctr then…
…
end loop inner;
end loop outer;
2.loop…exit…end loop
loop
sequence_of_statement;
…
exit;
end loop;
例:
loop
fetch c1 into …
exit when c1%notfound;
…
end loop;
close c1;
另:加loop label;
例:<<outer>>
loop
…
loop
…
exit outer when…
end loop;
…
end loop outer;
3.while…loop…end loop結構如下所示:
例
while total<=25000 loop
….
Select sa1 into salary from emp where…
Total:=total+salary;
End loop;
4.for…loop…
例1.
select count(empno) into emp_count from emp;
for L in 1..emp_count loop
…
end loop;
例2.
<<outer>>
for step in 1..25 loop
for step in 1..10 loop
…
if outer.step>15 then…
end loop;
end loop outer;
5. cursor….loop
declare
sursor c1 is select ename from emp;
name varchar2(100);
begin
for p_c1_rec in c1 loop
name := p_c1_rec.ename;
end loop;
四、
存儲過程
要創建存儲過程,可以使用下面的SQL和PL/SQL語句:
CREATE OR REPLACE PROCEDURE PROCEDURE_NAME(parameter list)
AS
…
BEGIN
…
(SQL AND PL/SQL COMMANDS)
END;
五、 存儲函數
create or replace function function_name (parameter list) return type is
….
Begin
…
…
end;
六、 Package
Package分為兩部分:Specific and Body
在包說明部分中,主要將此包中所含的過程和Function的調用參數說明清楚,如:
CREATE OR REPLACE PACKAGE ZDL_JOB_PKG
AS
PROCEDURE ZDL_INSERT_JOB(
p_bkc_id in number,
p_item_id in number,
p_job_number in out varchar2,
p_group_id in number,
p_lead_day in number,
p_load_type in number,
P_STATUS_TYPE IN NUMBER,
P_USER_ID IN NUMBER,
P_JOB_TYPE IN VARCHAR2);
PROCEDURE ZDL_UPDATE_JOB(
P_BKC_ID IN NUMBER,
P_GROUP_ID IN NUMBER,
P_STATUS_TYPE IN NUMBER,
P_USER_ID IN NUMBER);
FUNCTION WIP_MASS_LOAD(P_GROUP_ID IN NUMBER,P_USER_ID IN NUMBER) RETURN NUMBER;
PROCEDURE ZDL_PRE_UPDATE;
FUNCTION ZDL_UPDATE_ORACLE_WIP(P_USER_ID IN NUMBER) RETURN NUMBER;
FUNCTION ZDL_JOB_STATUS (P_JOB_NUMBER IN VARCHAR2) RETURN NUMBER;
END ZDL_JOB_PKG;
在包體部分,主要將包說明部分之過程及Function之代碼寫出來,
如:
CREATE OR REPLACE PACKAGE BODY ZDL_JOB_PKG
AS
PROCEDURE ZDL_INSERT_JOB (
p_bkc_id in number, p_item_id in number,p_job_number in out varchar2,
p_group_id in number,
p_lead_day in number,
P_LOAD_TYPE IN NUMBER,
P_STATUS_TYPE IN NUMBER,
P_USER_ID IN NUMBER,
P_JOB_TYPE IN VARCHAR2)
is
…………
begin
…………
end ZDL_INSERT_JOB;
PROCEDURE ZDL_UPDATE_JOB(P_BKC_ID IN NUMBER,P_GROUP_ID IN NUMBER,P_STATUS_TYPE IN NUMBER,P_USER_ID IN NUMBER)
AS
…………
BEGIN
…………
END ZDL_UPDATE_JOB;
FUNCTION WIP_MASS_LOAD(P_GROUP_ID IN NUMBER,P_USER_ID IN NUMBER) RETURN NUMBER
as
…………
begin
…………
END WIP_MASS_LOAD;
PROCEDURE ZDL_PRE_UPDATE IS
…………
begin
…………
end ZDL_PRE_UPDATE;
FUNCTION ZDL_UPDATE_ORACLE_WIP(P_USER_ID IN NUMBER) RETURN NUMBER
IS
…………
begin
…………
end ZDL_UPDATE_ORACLE_WIP;
FUNCTION ZDL_JOB_STATUS (P_JOB_NUMBER IN VARCHAR2) RETURN NUMBER
AS
…………
BEGIN
…………
END ZDL_JOB_STATUS;
END ZDL_JOB_PKG;
七、
觸發器
² 所需系統權限
要為某表創建觸發器,必須能改變這個表,因此不僅要擁有表,並且要具有這個表的 alter權限,或者具有alter any table系統權限,除此之外,必須有create triger系統權限,若要在另一個用戶賬號(account)(也稱之為模式(schema))上創建觸發器,就必具有create any trigger系統權限.
² 所需表權限
觸發器可以引用的表並不是初始化觸發事件的表.
² 觸發器
觸發器有十二種類型.一個觸發器的類型由執行觸發器的層次位置和觸發事務的類型定義.
² 行級觸發器
在某個事務中,行級觸發器行執行,對於上述ledger表中記例子而言,觸發器.行級觸發器是在create trigger命令中通過用for each row 子句創建的.
² 合法的觸發器類型
當兩種不同類型之觸發動作相結合時,有十二種可能的配置:
Before insert 行級觸發器
before insert 語句級觸發器
after insert 行級觸發器
after insert 語句級觸發器
before update 行級觸發器
before update 語句級觸發器
after update 行級觸發器
after update 語句級觸發器
before delete 行級觸發器
before delete 語句級觸發器
after delete 行級觸發器
after delete 語句級觸發器
例:
CREATE OR REPLACE TRIGGER "APPS"."ZDL_BKC_JOB_BODY_AFI"
AFTER INSERT ON "APPS"."ZDL_BKC_JOB_BODY"
REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW
BEGIN
Insert into audit_tbl values(:new.id,:new……);
UPDATE ZDL_BKC_JOB_HEAD SET UPDATE_DATE = SYSDATE
WHERE ZDL_BKC_JOB_HEAD_ID = :NEW.ZDL_BKC_JOB_BODY_ID;
END;
八、
應用實例
下面以電算部開發出之程序<<MDS展開及開工日維護程序>>之各類程序為例:
1. Create table, index, sequence, table trigger
首先清除原先已有之重名table,Sequence等:
DROP TABLE ZDL_BKC_JOB_BODY;
DROP TABLE ZDL_BKC_JOB_HEAD;
DROP TABLE ZDL_BKC_JOB_UPDATE;
drop sequence zdl_bkc_job_s;
建立table, sequence以及Index
create table zdl_bkc_job_head
(zdl_bkc_job_head_id number not null,
assembly varchar2(9) not null,
lot_no varchar2(240),
job_no varchar2(240),
OL_DATE date,
quantity number,
line_code varchar2(240),
created_date date,
update_date date,
primary key(zdl_bkc_job_head_id)
);
create table zdl_bkc_job_body
(zdl_bkc_job_body_id number not null references zdl_bkc_job_head(zdl_bkc_job_head_id),
level1 VARCHAR2(15),
job1 varchar2(240),
level2 VARCHAR2(15),
job2 varchar2(240),
level3 VARCHAR2(15),
job3 varchar2(240),
level4 VARCHAR2(15),
job4 varchar2(240),
level5 VARCHAR2(15),
job5 varchar2(240));
create table ZDL_BKC_JOB_UPDATE
( BKC_ID NUMBER NOT NULL,
LOCATION_ID NUMBER NOT NULL,
ACTION_ID NUMBER NOT NULL,
JOB_NUMBER VARCHAR2(240),
UPDATED_FLAG VARCHAR2(1),
CREATION_DATE DATE,
UPDATED_DATE DATE
);
create sequence zdl_bkc_job_s;
CREATE INDEX ZDL_BKC_JOB_HEAD_N1 ON ZDL_BKC_JOB_HEAD(ZDL_BKC_JOB_HEAD_ID,ASSEMBLY);
CREATE INDEX ZDL_BKC_JOB_BODY_N1 ON ZDL_BKC_jOB_BODY(ZDL_BKC_JOB_BODY_ID,LEVEL1);
CREATE INDEX ZDL_BKC_JOB_BODY_N2 ON ZDL_BKC_jOB_BODY(ZDL_BKC_JOB_BODY_ID,LEVEL2);
CREATE INDEX ZDL_BKC_JOB_BODY_N3 ON ZDL_BKC_jOB_BODY(ZDL_BKC_JOB_BODY_ID,LEVEL3);
CREATE INDEX ZDL_BKC_JOB_UPDATE_N1 ON ZDL_BKC_JOB_UPDATE(ACTION_ID,LOCATION_ID);
COMMIT;
建立table Trigger:
-- Trigger head after update
CREATE OR REPLACE TRIGGER "APPS".ZDL_BKC_JOB_HEAD_AFU
AFTER UPDATE OF "LINE_CODE", "LOT_NO", "OL_DATE", "QUANTITY" ON "APPS"."ZDL_BKC_JOB_HEAD"
REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW
BEGIN
INSERT INTO ZDL_BKC_JOB_UPDATE (
BKC_ID,
LOCATION_ID,
ACTION_ID,
JOB_NUMBER,
UPDATED_FLAG,
CREATION_DATE,
UPDATED_DATE)
VALUES(
:OLD.ZDL_BKC_JOB_HEAD_ID,
1,
3,
:OLD.JOB_NO,
'N',
SYSDATE,
SYSDATE);
END;
-- Trigger body before delete
CREATE OR REPLACE TRIGGER "APPS"."ZDL_BKC_JOB_BODY_BRD"
BEFORE DELETE ON "APPS"."ZDL_BKC_JOB_BODY"
REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW
BEGIN
if :old.job1 is not null then
INSERT INTO ZDL_BKC_JOB_UPDATE(BKC_ID,LOCATION_ID,ACTION_ID,JOB_NUMBER,UPDATED_FLAG,CREATION_DATE,UPDATED_DATE)
VALUES(:OLD.ZDL_BKC_JOB_BODY_ID,2,7,:old.JOB1,'N',SYSDATE,SYSDATE);
END IF;
if :old.job2 is not null then
INSERT INTO ZDL_BKC_JOB_UPDATE(BKC_ID,LOCATION_ID,ACTION_ID,JOB_NUMBER,UPDATED_FLAG,CREATION_DATE,UPDATED_DATE)
VALUES(:OLD.ZDL_BKC_JOB_BODY_ID,2,7,:old.JOB2,'N',SYSDATE,SYSDATE);
END IF;
if :old.job3 is not null then
INSERT INTO ZDL_BKC_JOB_UPDATE(BKC_ID,LOCATION_ID,ACTION_ID,JOB_NUMBER,UPDATED_FLAG,CREATION_DATE,UPDATED_DATE)
VALUES(:OLD.ZDL_BKC_JOB_BODY_ID,2,7,:old.JOB3,'N',SYSDATE,SYSDATE);
END IF;
if :old.job4 is not null then
INSERT INTO ZDL_BKC_JOB_UPDATE(BKC_ID,LOCATION_ID,ACTION_ID,JOB_NUMBER,UPDATED_FLAG,CREATION_DATE,UPDATED_DATE)
VALUES(:OLD.ZDL_BKC_JOB_BODY_ID,2,7,:old.JOB4,'N',SYSDATE,SYSDATE);
END IF;
if :old.job5 is not null then
INSERT INTO ZDL_BKC_JOB_UPDATE(BKC_ID,LOCATION_ID,ACTION_ID,JOB_NUMBER,UPDATED_FLAG,CREATION_DATE,UPDATED_DATE)
VALUES(:OLD.ZDL_BKC_JOB_BODY_ID,2,7,:old.JOB5,'N',SYSDATE,SYSDATE);
END IF;
UPDATE ZDL_BKC_JOB_HEAD SET UPDATE_DATE = SYSDATE
WHERE ZDL_BKC_JOB_HEAD_ID = :OLD.ZDL_BKC_JOB_BODY_ID;
END;
-- Trigger head after delete
CREATE OR REPLACE TRIGGER "APPS".ZDL_BKC_JOB_HEAD_BRD
BEFORE DELETE ON "APPS"."ZDL_BKC_JOB_HEAD"
REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW
BEGIN
INSERT INTO ZDL_BKC_JOB_UPDATE
(BKC_ID,LOCATION_ID,ACTION_ID,JOB_NUMBER,UPDATED_FLAG,CREATION_DATE,UPDATED_DATE)
VALUES
(:OLD.ZDL_BKC_JOB_HEAD_ID,1,7,:OLD.JOB_NO,'N',SYSDATE,SYSDATE);
END;
-- Trigger body after insert
CREATE OR REPLACE TRIGGER "APPS"."ZDL_BKC_JOB_BODY_AFI"
AFTER INSERT ON "APPS"."ZDL_BKC_JOB_BODY"
REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW
BEGIN
UPDATE ZDL_BKC_JOB_HEAD SET UPDATE_DATE = SYSDATE
WHERE ZDL_BKC_JOB_HEAD_ID = :NEW.ZDL_BKC_JOB_BODY_ID;
END;
2. 建立兩個主要之package:
A. ZDL_BKC_APP_PKG
Package Specific
CREATE OR REPLACE PACKAGE ZDL_BKC_APP_PKG
AS
/*BOM之展開*/
PROCEDURE ZDL_BOM_EXPLOSION(
P_ITEM_ID IN NUMBER,
p_Organization_id IN NUMBER,
P_BOM_GROUP_ID IN NUMBER,
P_EXPL_QTY IN NUMBER,
P_ERROR_CODE OUT NUMBER);
/*展開之半制品放於ZDL_JOB_BKC_HEAD AND ZDL_JOB_BKC_BODY中,並調用ZDL_JOB_PKG中的
相閞過程實現JOB之產生及LOAD入Oracle MFG中*/
PROCEDURE ZDL_PROCESS_BOM(
P_ITEM_ID in number,
P_BKC_ID OUT NUMBER,
P_BOM_GROUP_ID IN NUMBER,
P_GROUP_ID IN NUMBER,
P_SCHEDULE_COMMENTS IN VARCHAR2,
P_SCHEDULE_QUANTITY IN NUMBER,
P_SCHEDULE_DATE IN DATE,
P_ORGANIZATION_ID IN NUMBER,
P_USER_ID IN NUMBER,
P_ERROR_CODE OUT NUMBER,
P_JOB_TYPE IN VARCHAR2);
END ZDL_BKC_APP_PKG;
Package Body
CREATE OR REPLACE PACKAGE BODY ZDL_BKC_APP_PKG
AS
PROCEDURE ZDL_BOM_EXPLOSION(
P_ITEM_ID IN NUMBER,
p_Organization_id IN NUMBER,
P_BOM_GROUP_ID IN NUMBER,
P_EXPL_QTY IN NUMBER,
P_ERROR_CODE OUT NUMBER)
AS
l_seq_id NUMBER;
l_bom_or_eng NUMBER:=1;
l_err_msg VARCHAR2(80);
l_err_code NUMBER;
exploder_error EXCEPTION;
loop_error EXCEPTION;
table_name VARCHAR2(20);
item_id_null EXCEPTION;
p_revision_date varchar2(15);
P_EXPLODE_OPTION_TYPE varchar2(100);
BEGIN
P_ERROR_CODE := 0;
SELECT BOM_LISTS_S.NEXTVAL
INTO l_seq_id
FROM DUAL;
TABLE_NAME := 'BUILD SQL';
INSERT INTO BOM_LISTS (SEQUENCE_ID, ASSEMBLY_ITEM_ID,
ALTERNATE_DESIGNATOR)
SELECT DISTINCT l_seq_id,P_ITEM_ID,
bbom.alternate_bom_designator
FROM bom_bill_of_materials bbom
WHERE bbom.organization_id = 102
AND bbom.assembly_item_id = P_ITEM_ID
AND (bbom.alternate_bom_designator IS NULL)
AND (bbom.assembly_type = 1);
commit;
TABLE_NAME := 'EXECUTE SQL';
/* Call BOM exploder */
TABLE_NAME := 'CALL EXPLODER';
-- bug 519321
P_REVISION_DATE := to_char(sysdate,'DD-MON-YY HH24:MI');
bompexpl.explosion_report
(
org_id => p_Organization_id,
order_by => 2,
list_id => l_seq_id,
grp_id => P_BOM_GROUP_ID,
session_id => -1,
levels_to_explode => 15,
bom_or_eng => 1,
impl_flag => 1,
explode_option => 2,
module => 2,
cst_type_id => -1,
std_comp_flag => -1,
expl_qty => P_EXPL_QTY,
report_option => -1,
req_id => 0,
lock_flag => -1,
rollup_option => -1,
alt_rtg_desg => '',
alt_desg => '',
rev_date => P_REVISION_DATE,
err_msg => l_err_msg,
error_code => l_err_code,
verify_flag =>0,
cst_rlp_id => 0,
plan_factor_flag => 2,
incl_lt_flag => 2
);
commit;
TABLE_NAME := 'EXPLODE COMPLETE';
if l_err_code = 9999 then
raise loop_error;
end if;
if l_err_code <0 then
raise exploder_error;
end if;
commit; --save
DELETE FROM BOM_LISTS WHERE SEQUENCE_ID = L_SEQ_ID;
COMMIT;
EXCEPTION
WHEN exploder_error THEN
P_ERROR_CODE := 1;
dbms_output.put_line(l_err_msg);
WHEN loop_error THEN
P_ERROR_CODE := 2;
dbms_output.put_line('aaa');
WHEN item_id_null THEN
P_ERROR_CODE := 3;
dbms_output.put_line('Item is is null');
WHEN NO_DATA_FOUND THEN
P_ERROR_CODE := 4;
dbms_output.put_line(TABLE_NAME ||SQLERRM);
WHEN OTHERS THEN
P_ERROR_CODE := 5;
dbms_output.put_line(TABLE_NAME || SQLERRM);
END ZDL_BOM_EXPLOSION;
/* Process data of bom_explosion_temp */
PROCEDURE ZDL_PROCESS_BOM(
P_ITEM_ID in number,
P_BKC_ID OUT NUMBER,
P_BOM_GROUP_ID IN NUMBER,
P_GROUP_ID IN NUMBER,
P_SCHEDULE_COMMENTS IN VARCHAR2,
P_SCHEDULE_QUANTITY IN NUMBER,
P_SCHEDULE_DATE IN DATE,
P_ORGANIZATION_ID IN NUMBER,
P_USER_ID IN NUMBER,
P_ERROR_CODE OUT NUMBER,
P_JOB_TYPE IN VARCHAR2)
AS
CURSOR C1 IS
SELECT
BET.ASSEMBLY_ITEM_ID,
MSI.SEGMENT1,
BET.COMPONENT_ITEM_ID,
BET.PLAN_LEVEL
FROM BOM.BOM_EXPLOSION_TEMP BET,
INV.MTL_SYSTEM_ITEMS MSI
WHERE
BET.COMPONENT_ITEM_ID = MSI.INVENTORY_ITEM_ID AND
BET.ORGANIZATION_ID = MSI.ORGANIZATION_ID AND
MSI.ORGANIZATION_ID = P_ORGANIZATION_ID AND
BET.GROUP_ID = P_BOM_GROUP_ID AND
BET.TOP_ITEM_ID = P_ITEM_ID AND
(MSI.ITEM_TYPE = 'SA' OR MSI.ITEM_TYPE = 'FG')
ORDER BY BET.PLAN_LEVEL;
P_C1 C1%ROWTYPE;
R_ITEM VARCHAR2(15);
P_JOB_NUMBER NUMBER;
BEGIN
P_ERROR_CODE := 0;
OPEN C1;
LOOP
FETCH C1 INTO P_C1;
EXIT WHEN C1%NOTFOUND;
IF P_C1.PLAN_LEVEL = 0 THEN
select zdl_bkc_job_s.nextval into P_BKC_ID from sys.dual;
insert into zdl_bkc_job_head
( zdl_bkc_job_head_id,
assembly,
CREATED_DATE,
update_date,
QUANTITY,
LOT_NO,
LINE_CODE,
OL_DATE)
values
( P_BKC_ID,
P_item_ID,
SYSDATE,
SYSDATE,
P_SCHEDULE_QUANTITY,
SUBSTR(P_SCHEDULE_COMMENTS,1,INSTR(P_SCHEDULE_COMMENTS,'/')-1),
SUBSTR(P_SCHEDULE_COMMENTS,INSTR(P_SCHEDULE_COMMENTS,'/')+1,
LENGTH(P_SCHEDULE_COMMENTS)),
P_SCHEDULE_DATE);
COMMIT;
ZDL_JOB_PKG.ZDL_INSERT_JOB(P_BKC_ID,P_ITEM_ID,P_JOB_NUMBER,P_GROUP_ID,
0,1,0,P_USER_ID,P_JOB_TYPE);
UPDATE ZDL_BKC_JOB_HEAD SET JOB_NO = P_JOB_NUMBER WHERE ZDL_BKC_JOB_HEAD_ID = P_BKC_ID;
ELSIF P_C1.PLAN_LEVEL = 1 THEN
ZDL_JOB_PKG.zdl_insert_job(P_BKC_ID,P_C1.COMPONENT_ITEM_ID,p_job_number,p_group_id,
-2,1,0,P_USER_ID,P_JOB_TYPE);
insert into zdl_bkc_job_body
(zdl_bkc_job_body_id,level1,job1)
values(P_BKC_ID,P_C1.SEGMENT1,p_job_number);
COMMIT;
ELSIF P_C1.PLAN_LEVEL = 2 THEN
SELECT SEGMENT1 INTO R_ITEM
FROM MTL_SYSTEM_ITEMS
WHERE ORGANIZATION_ID = P_ORGANIZATION_ID
AND INVENTORY_ITEM_ID = P_C1.ASSEMBLY_ITEM_ID;
ZDL_JOB_PKG.ZDL_INSERT_JOB(P_BKC_ID,P_C1.COMPONENT_ITEM_ID,P_JOB_NUMBER,P_GROUP_ID,
-3,1,0,P_USER_ID,P_JOB_TYPE);
UPDATE ZDL_BKC_JOB_BODY SET
LEVEL2 = P_C1.SEGMENT1,
JOB2 = P_JOB_NUMBER
WHERE LEVEL1 = R_ITEM AND ZDL_BKC_JOB_BODY_ID = P_BKC_ID;
COMMIT;
ELSIF P_C1.PLAN_LEVEL = 3 THEN
SELECT SEGMENT1 INTO R_ITEM
FROM MTL_SYSTEM_ITEMS
WHERE ORGANIZATION_ID = P_ORGANIZATION_ID
AND INVENTORY_ITEM_ID = P_C1.ASSEMBLY_ITEM_ID;
ZDL_JOB_PKG.ZDL_INSERT_JOB(P_BKC_ID,P_C1.COMPONENT_ITEM_ID,P_JOB_NUMBER,P_GROUP_ID,
-4,1,0,P_USER_ID,P_JOB_TYPE);
UPDATE ZDL_BKC_JOB_BODY SET
LEVEL3 = P_C1.SEGMENT1,
JOB3 = P_JOB_NUMBER
WHERE LEVEL2 = R_ITEM AND ZDL_BKC_JOB_BODY_ID = P_BKC_ID;
COMMIT;
ELSIF P_C1.PLAN_LEVEL = 4 THEN
SELECT SEGMENT1 INTO R_ITEM
FROM MTL_SYSTEM_ITEMS
WHERE ORGANIZATION_ID = P_ORGANIZATION_ID
AND INVENTORY_ITEM_ID = P_C1.ASSEMBLY_ITEM_ID;
ZDL_JOB_PKG.ZDL_INSERT_JOB(P_BKC_ID,P_C1.COMPONENT_ITEM_ID,P_JOB_NUMBER,P_GROUP_ID,
-6,1,0,P_USER_ID,P_JOB_TYPE);
UPDATE ZDL_BKC_JOB_BODY SET
LEVEL4 = P_C1.SEGMENT1,
JOB3 = P_JOB_NUMBER
WHERE LEVEL3 = R_ITEM AND ZDL_BKC_JOB_BODY_ID = P_BKC_ID;
COMMIT;
ELSIF P_C1.PLAN_LEVEL = 5 THEN
SELECT SEGMENT1 INTO R_ITEM
FROM MTL_SYSTEM_ITEMS
WHERE ORGANIZATION_ID = P_ORGANIZATION_ID
AND INVENTORY_ITEM_ID = P_C1.ASSEMBLY_ITEM_ID;
ZDL_JOB_PKG.ZDL_INSERT_JOB(P_BKC_ID,P_C1.COMPONENT_ITEM_ID,P_JOB_NUMBER,P_GROUP_ID,
-6,1,0,P_USER_ID,P_JOB_TYPE);
UPDATE ZDL_BKC_JOB_BODY SET
LEVEL5 = P_C1.SEGMENT1,
JOB3 = P_JOB_NUMBER
WHERE LEVEL4 = R_ITEM AND ZDL_BKC_JOB_BODY_ID = P_BKC_ID;
COMMIT;
END IF;
END LOOP;
CLOSE C1;
DELETE FROM BOM_EXPLOSION_TEMP WHERE GROUP_ID = P_BOM_GROUP_ID;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
P_ERROR_CODE := 6;
END ZDL_PROCESS_BOM;
END ZDL_BKC_APP_PKG;
B. ZDL_JOB_PKG
Package Specific
CREATE OR REPLACE PACKAGE ZDL_JOB_PKG
AS
/*給每個展開之半制品分配一個JOB號,並將其存儲於WIP_JOB_SCHEDULE_INTERFACE中*/
PROCEDURE ZDL_INSERT_JOB(
p_bkc_id in number,
p_item_id in number,
p_job_number in out varchar2,
p_group_id in number,
p_lead_day in number,
p_load_type in number,
P_STATUS_TYPE IN NUMBER,
P_USER_ID IN NUMBER,
P_JOB_TYPE IN VARCHAR2);
/*維護O/L日期等時自動更新Oracle MFG之WIP*/
PROCEDURE ZDL_UPDATE_JOB(
P_BKC_ID IN NUMBER,
P_GROUP_ID IN NUMBER,
P_STATUS_TYPE IN NUMBER,
P_USER_ID IN NUMBER);
/*觸發WIP JOB MASS LOAD程序*/
FUNCTION WIP_MASS_LOAD(P_GROUP_ID IN NUMBER,P_USER_ID IN NUMBER) RETURN NUMBER;
/*在使用ZDL_BKC_JOB_UPDATE檔更新Oracle MFG時,將其中之相關數據織一下*/
PROCEDURE ZDL_PRE_UPDATE;
/*調用前面之相關程序,並根據ZDL_BKC_JOB_UPDATE文件更新Oracle MFG*/
FUNCTION ZDL_UPDATE_ORACLE_WIP(P_USER_ID IN NUMBER) RETURN NUMBER;
/*檢查Oracle JOB之狀態,並返回*/
FUNCTION ZDL_JOB_STATUS (P_JOB_NUMBER IN VARCHAR2) RETURN NUMBER;
END ZDL_JOB_PKG;
Package Body
CREATE OR REPLACE PACKAGE BODY ZDL_JOB_PKG
AS
PROCEDURE ZDL_INSERT_JOB (
p_bkc_id in number,
p_item_id in number,
p_job_number in out varchar2,
p_group_id in number,
p_lead_day in number,
P_LOAD_TYPE IN NUMBER,
P_STATUS_TYPE IN NUMBER,
P_USER_ID IN NUMBER,
P_JOB_TYPE IN VARCHAR2)
is
p_completion_date date;
r_schedule_date date;
p_start_quantity number;
l_seq_num number;
l_next_seq_num number;
p_lot_number varchar2(240);
P_LINE_CODE VARCHAR2(240);
p_wip_entity_id number;
begin
/* P_BKC_ID = 0 MEAN THAT THE BKC ID HAS BEEN DELETE FROM TABLE */
IF NOT (P_BKC_ID = 0 AND P_STATUS_TYPE = 7) THEN
select OL_DATE,quantity,lot_no,line_code into p_completion_date,p_start_quantity,p_lot_number,P_LINE_CODE
from zdl_bkc_job_head where ZDL_BKC_JOB_HEAD_ID = p_bkc_id;
END IF;
/* P_STSTUS_TYPE = 7 MEAD THAT THIS JOB MUST BE CANCELLED */
IF P_STATUS_TYPE <> 7 THEN
select seq_num,next_seq_num into l_seq_num,l_next_seq_num
from bom_calendar_dates
where trunc(calendar_date) = trunc(p_completion_date);
if l_seq_num is null then
l_seq_num:=l_next_seq_num-1;
end if;
l_seq_num:=l_seq_num+p_lead_day;
select calendar_date into r_schedule_date from bom_calendar_dates where seq_num=l_seq_num;
END IF;
/* P_LOAD_TYPE = 1 : ADD A JOB INTO ORACLE WIP
P_LOAD_TYPE = 3 : UPDATE A JOB OF ORACLE WIP*/
if p_load_type = 1 then
select wip_job_number_s.nextval into p_job_number from sys.dual;
elsif p_load_type = 3 then
select wip_entity_id into p_wip_entity_id from wip_entities where wip_entity_name = p_job_number;
end if;
insert into wip_job_schedule_interface
(
last_update_date,
creation_date,
created_by,
last_updated_by,
group_id,
process_phase,
process_status,
load_type,
job_name,
wip_entity_id,
LAST_UNIT_COMPLETION_DATE,
organization_id,
primary_item_id,
description,
start_quantity,
STATUS_TYPE,
ATTRIBUTE_CATEGORY,
ATTRIBUTE1,
ATTRIBUTE2,
ATTRIBUTE3)
values
( sysdate,
sysdate,
P_USER_ID,
P_USER_ID,
p_group_id,
2,
1,
P_LOAD_TYPE,
p_job_number,
decode(p_load_type,1,null,p_wip_entity_id),
DECODE(P_STATUS_TYPE,0,to_date(to_char(r_schedule_date,'DD-MON-YYYY HH24:MI:SS'),
'DD-MON-YYYY HH24:MI:SS'),NULL),
102,
decode(p_load_type,1,p_item_id,null),
decode(p_load_type,1,'Created By ZDL BKC Program',DECODE(P_STATUS_TYPE,0,
'Updated by ZDL BKC Program','Cancelled by ZDL BKC Program')),
DECODE(P_STATUS_TYPE,0,p_start_quantity,NULL),
DECODE(P_STATUS_TYPE,0,NULL,P_STATUS_TYPE),
'JOB',
DECODE(P_LOAD_TYPE,1,P_JOB_TYPE,NULL),
p_lot_number,
P_LINE_CODE
);
commit;
end ZDL_INSERT_JOB;
PROCEDURE ZDL_UPDATE_JOB(P_BKC_ID IN NUMBER,P_GROUP_ID IN NUMBER,
P_STATUS_TYPE IN NUMBER,P_USER_ID IN NUMBER)
AS
P_JOB_NO VARCHAR2(240);
P_LOT_NO VARCHAR2(240);
P_QUANTITY NUMBER;
P_LINE_CODE VARCHAR2(240);
P_OL_DATE DATE;
p_job1 zdl_bkc_job_body.job1%type;
p_job2 zdl_bkc_job_body.job2%type;
p_job3 zdl_bkc_job_body.job3%type;
p_job4 zdl_bkc_job_body.job4%type;
p_job5 zdl_bkc_job_body.job5%type;
cursor l_bkc is
select job1,job2,job3,job4,job5 from zdl_bkc_job_body where zdl_bkc_job_body_id=p_bkc_id;
BEGIN
SELECT JOB_NO,LOT_NO,QUANTITY,LINE_CODE,OL_DATE
INTO P_JOB_NO,P_LOT_NO,P_QUANTITY,P_LINE_CODE,P_OL_DATE
FROM ZDL_BKC_JOB_HEAD
WHERE ZDL_BKC_JOB_HEAD_ID = P_BKC_ID;
zdl_job_pkg.ZDL_INSERT_JOB(P_BKC_ID,0,p_job_no,p_group_id,0,3,P_STATUS_TYPE,P_USER_ID,NULL);
open l_bkc;
loop
fetch l_bkc into p_job1,p_job2,p_job3,p_job4,p_job5;
exit when l_bkc%notfound;
if P_job1 is not null then
zdl_job_pkg.ZDL_INSERT_JOB(P_BKC_ID,0,P_JOB1,P_GROUP_ID,-2,3,P_STATUS_TYPE,P_USER_ID,NULL);
end if;
IF P_JOB2 IS NOT NULL THEN
zdl_job_pkg.ZDL_INSERT_JOB(P_BKC_ID,0,P_JOB2,P_GROUP_ID,-3,3,P_STATUS_TYPE,P_USER_ID,NULL);
END IF;
IF P_JOB3 IS NOT NULL THEN
zdl_job_pkg.ZDL_INSERT_JOB(P_BKC_ID,0,P_JOB3,P_GROUP_ID,-4,3,P_STATUS_TYPE,P_USER_ID,NULL);
END IF;
IF P_JOB4 IS NOT NULL THEN
zdl_job_pkg.ZDL_INSERT_JOB(P_BKC_ID,0,P_JOB4,P_GROUP_ID,-6,3,P_STATUS_TYPE,P_USER_ID,NULL);
END IF;
IF P_JOB5 IS NOT NULL THEN
zdl_job_pkg.ZDL_INSERT_JOB(P_BKC_ID,0,P_JOB5,P_GROUP_ID,-8,3,P_STATUS_TYPE,P_USER_ID,NULL);
END IF;
end loop;
END ZDL_UPDATE_JOB;
FUNCTION WIP_MASS_LOAD(P_GROUP_ID IN NUMBER,P_USER_ID IN NUMBER) RETURN NUMBER
as
req_id number;
LOGINID NUMBER;
begin
SELECT FND_CONCURRENT_REQUESTS_S.NEXTVAL INTO REQ_ID FROM DUAL;
SELECT FND_LOGINS_S.NEXTVAL INTO LOGINID FROM DUAL;
insert into FND_CONCURRENT_REQUESTS (
REQUEST_ID,
LAST_UPDATE_DATE,
LAST_UPDATED_BY,
LAST_UPDATE_LOGIN,
REQUEST_DATE,
REQUESTED_BY,
PHASE_CODE,
STATUS_CODE,
PRIORITY_REQUEST_ID,
PRIORITY,
REQUESTED_START_DATE,
HOLD_FLAG,
ENFORCE_SERIALITY_FLAG,
SINGLE_THREAD_FLAG,
HAS_SUB_REQUEST,
IS_SUB_REQUEST,
IMPLICIT_CODE,
UPDATE_PROTECTED,
QUEUE_METHOD_CODE,
ARGUMENT_INPUT_METHOD_CODE,
ORACLE_ID,
PROGRAM_APPLICATION_ID,
CONCURRENT_PROGRAM_ID,
RESPONSIBILITY_APPLICATION_ID,
RESPONSIBILITY_ID,
NUMBER_OF_ARGUMENTS,
NUMBER_OF_COPIES,
SAVE_OUTPUT_FLAG,
NLS_LANGUAGE,
NLS_TERRITORY,
PRINTER,
PRINT_STYLE,
PRINT_GROUP,
REQUEST_CLASS_APPLICATION_ID,
CONCURRENT_REQUEST_CLASS_ID,
PARENT_REQUEST_ID,
CONC_LOGIN_ID,
LANGUAGE_ID,
DESCRIPTION,
REQ_INFORMATION,
RESUBMIT_INTERVAL,
RESUBMIT_INTERVAL_UNIT_CODE,
RESUBMIT_INTERVAL_TYPE_CODE,
RESUBMIT_TIME,
RESUBMIT_END_DATE,
RESUBMITTED,
CONTROLLING_MANAGER,
ACTUAL_START_DATE,
ACTUAL_COMPLETION_DATE,
COMPLETION_TEXT,
OUTCOME_PRODUCT,
OUTCOME_CODE,
CPU_SECONDS,
LOGICAL_IOS,
PHYSICAL_IOS,
LOGFILE_NAME,
LOGFILE_NODE_NAME,
OUTFILE_NAME,
OUTFILE_NODE_NAME,
ARGUMENT_TEXT,
ARGUMENT1,
ARGUMENT2,
ARGUMENT3,
ARGUMENT4,
ARGUMENT5,
ARGUMENT6,
ARGUMENT7,
ARGUMENT8,
ARGUMENT9,
ARGUMENT10,
ARGUMENT11,
ARGUMENT12,
ARGUMENT13,
ARGUMENT14,
ARGUMENT15,
ARGUMENT16,
ARGUMENT17,
ARGUMENT18,
ARGUMENT19,
ARGUMENT20,
ARGUMENT21,
ARGUMENT22,
ARGUMENT23,
ARGUMENT24,
ARGUMENT25,
CRM_THRSHLD,
CRM_TSTMP
)
VALUES
(
REQ_ID,
SYSDATE,
P_USER_ID,
LOGINID,
SYSDATE,
P_USER_ID,
'P',
'I',
REQ_ID,
50,
SYSDATE,
'N',
'Y',
'N',
'N',
'N',
'N',
'N',
'I',
'S',
900,
706,
34291,
706,
20560,
3,
0,
'Y',
'AMERICAN',
'AMERICA',
NULL,
'LANDSCAPE',
'N',
NULL,
NULL,
-1,
LOGINID,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
'N',
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
RTRIM(TO_CHAR(P_GROUP_ID))||', 0, 1',
P_GROUP_ID,
0,
1,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL
);
COMMIT;
return(req_id);
END WIP_MASS_LOAD;
PROCEDURE ZDL_PRE_UPDATE IS
cursor c1 is
select rowid,bkc_id,location_id,action_id,job_number
from zdl_bkc_job_update where updated_flag = 'N';
p_c1_rec c1%rowtype;
p_count number default 0;
begin
delete
from zdl_bkc_job_update z1
where rowid !=
(select
max(rowid)
from
zdl_bkc_job_update z2
where
z1.bkc_id = z2.bkc_id and
z1.location_id = z2.location_id and
z1.action_id = z2.action_id and
z1.job_number = z2.job_number AND
Z1.UPDATED_FLAG = z2.updated_flag)
and z1.updated_flag = 'N';
commit;
open c1;
loop
fetch c1 into p_c1_rec;
exit when c1%notfound;
if p_c1_rec.action_id = 3 then
select count(*) into p_count
from zdl_bkc_job_update
where bkc_id = p_c1_rec.bkc_id and
location_id = p_c1_rec.location_id and
action_id = 7 and
job_number = p_c1_rec.job_number AND UPDATED_FLAG = 'N';
if p_count > 0 then
delete from zdl_bkc_job_update
where rowid = p_c1_rec.rowid;
commit;
end if;
end if;
end loop;
end ZDL_PRE_UPDATE;
FUNCTION ZDL_UPDATE_ORACLE_WIP(P_USER_ID IN NUMBER) RETURN NUMBER
IS
P_GROUP_ID NUMBER;
P_REQ_ID NUMBER;
p_bkc_id number;
p_action_id number;
p_location_id number;
p_job_number varchar2(240);
p_count boolean default false;
p_count_item number;
cursor c1 is
select bkc_id,action_id,location_id,job_number
from zdl_bkc_job_update
where action_id = 3 and location_id = 1 AND UPDATED_FLAG = 'N';
cursor c2 is
select bkc_id,action_id,location_id,job_number
from zdl_bkc_job_update
where action_id = 7 AND UPDATED_FLAG = 'N';
begin
ZDL_JOB_PKG.ZDL_PRE_UPDATE;
select wip_job_schedule_interface_s.nextval into p_group_id from sys.dual;
open c1;
loop
fetch c1 into p_bkc_id,p_action_id,p_location_id,p_job_number;
exit when c1%notfound;
zdl_job_pkg.zdl_update_job(p_bkc_id,p_group_id,0,P_USER_ID);
end loop;
if c1%rowcount > 0 then
UPDATE zdl_bkc_job_update SET UPDATED_FLAG = 'Y',UPDATED_DATE = SYSDATE
where action_id = 3 and location_id = 1 AND UPDATED_FLAG = 'N';
p_count := true;
end if;
close c1;
commit;
open c2;
loop
fetch c2 into p_bkc_id,p_action_id,p_location_id,p_job_number;
exit when c2%notfound;
zdl_job_pkg.zdl_insert_job(0,0,p_job_number,p_group_id,0,3,7,P_USER_ID,NULL);
end loop;
if c2%rowcount > 0 then
p_count := true;
UPDATE zdl_bkc_job_update SET UPDATED_FLAG = 'Y',UPDATED_DATE = SYSDATE
where action_id = 7 AND UPDATED_FLAG = 'N';
end if;
close c2;
commit;
if p_count then
P_REQ_ID := ZDL_JOB_PKG.WIP_MASS_LOAD(P_GROUP_ID,P_USER_ID);
else
p_req_id := 0;
end if;
RETURN(P_REQ_ID);
end ZDL_UPDATE_ORACLE_WIP;
FUNCTION ZDL_JOB_STATUS (P_JOB_NUMBER IN VARCHAR2) RETURN NUMBER
AS
P_STATUS_TYPE NUMBER;
BEGIN
SELECT
STATUS_TYPE INTO P_STATUS_TYPE
FROM
WIP_DISCRETE_JOBS WDJ,
WIP_ENTITIES WE
WHERE WE.WIP_ENTITY_ID = WDJ.WIP_ENTITY_ID AND
WDJ.ORGANIZATION_ID = WE.ORGANIZATION_ID AND
WE.WIP_ENTITY_NAME = P_JOB_NUMBER;
RETURN (P_STATUS_TYPE);
END ZDL_JOB_STATUS;
END ZDL_JOB_PKG;
自我補充:
日期函數:
1、 求某天是星期幾
select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day') from dual;
星期一
select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;
monday
設置日期語言
ALTER SESSION SET NLS_DATE_LANGUAGE='AMERICAN';
也可以這樣
TO_DATE ('2002-08-26', 'YYYY-mm-dd', 'NLS_DATE_LANGUAGE = American')
2、 兩個日期間的天數
select floor(sysdate - to_date('20020405','yyyymmdd')) from dual;
3、 時間為null的用法
select id, active_date from table1
UNION
select 1, TO_DATE(null) from dual;
注意要用TO_DATE(null)
4、 處理月份天數不定的辦法
select to_char(add_months(last_day(sysdate) +1, -2), 'yyyymmdd'),last_day(sysdate) from dual
5、 找出今年的天數
select add_months(trunc(sysdate,'year'), 12) - trunc(sysdate,'year') from dual
6、 閏年的處理方法
to_char( last_day( to_date('02' || :year,'mmyyyy') ), 'dd' )
如果是28就不是閏年
7、 5秒鍾一個間隔
Select TO_DATE(FLOOR(TO_CHAR(sysdate,'SSSSS')/300) * 300,'SSSSS') ,TO_CHAR(sysdate,'SSSSS')
from dual
2002-11-1 9:55:00 35786
SSSSS表示5位秒數
8、 一年的第幾天
select TO_CHAR(SYSDATE,'DDD'),sysdate from dual
310 2002-11-6 10:03:51
9、 floor((date2-date1) /365) 作為年
floor((date2-date1, 365) /30) 作為月
mod(mod(date2-date1, 365), 30)作為日.
23.next_day函數
next_day(sysdate,6)是從當前開始下一個星期五。后面的數字是從星期日開始算起。
1 2 3 4 5 6 7
日 一 二 三 四 五 六
10、 extract()找出日期或間隔值的字段值
date_value:=extract(date_field from [datetime_value|interval_value])
SQL> select extract(month from sysdate) "This Month" from dual;
This Month
----------
11
SQL> select extract(year from add_months(sysdate,36)) "3 Years Out" from dual;
3 Years Out
-----------
2006
11、 localtimestamp()返回會話中的日期和時間
timestamp_value:=localtimestamp
SQL> column localtimestamp format a28
SQL> select localtimestamp from dual;
LOCALTIMESTAMP
----------------------------
13-11月-03 12.09.15.433000
下午
12、 decode()函數
先構造一個例子,假設我們想給智星職員加工資,其標准是:工資在8000元以下的將加20%;工資在8000元以上的加15%,通常的做法是,先選出記錄中的工資字段值? select salary into var-salary from employee,然后對變量var-salary用if-then-else或choose case之類的流控制語句進行判斷。 如果用DECODE函數,那么我們就可以把這些流控制語句省略,通過SQL語句就可以直接完成。如下:select decode(sign(salary - 8000),1,salary*1.15,-1,salary*1.2,salary from employee 是不是很簡潔?
使用方法:
1、比較大小
select decode(sign(變量1-變量2),-1,變量1,變量2) from dual; --取較小值
sign()函數根據某個值是0、正數還是負數,分別返回0、1、-1