Oracle”文字”報表輸出
Oracle”文字”報表輸出
Sam.T
2012-12-12
現象:
一個普通的XML或者PL/SQL過程匯出的Oracle報表,用Excel開啟,第一次存檔的時候,可能很大(之前碰到過,一財務的MM用XML報表導2年的資料,文件體積超過50M,而她們的電腦配置低,文件沒法開啟。尷尬。);但是用Excel另存為一個新的Excel文件之後,容量會小很多。為什麼?
就是因為,通常我們看到的文件內容,事實上後面有大量的格式控制程式碼(特別是XML),這些程式碼也會佔用很多容量,導致開啟文件的時候會很慢。當你將這個Excel文件另存之後,Excel會將這些程式碼去掉,所以容量小很多。
XML的格式程式碼見下圖,每個欄位都有:
實現思路:
先說明一下,此方法只適合(大量的)資料匯出。就是對資料的顯示格式沒要求的話可以考慮用這個方法。如果對格式要求很高(例如發貨單/銷售單列印),還是乖乖用XML開發吧,這種一般是單對單的列印,容量大不了哪裡去。
所以現在的目的主要是為了節省輸出的文字字元。通常的包輸出Excel文件的Procedure報表的開發,實際上是開發網頁,一個顯示Excel文件的網頁。眾多的網頁控制程式碼(tr/td等等的網頁格式控制程式碼),佔用了很大空間。別小看這個,如果一個報表要輸出幾十萬行的資料,就是網頁格式控制程式碼都佔用不少空間。同理,XML的也一樣。
所以,基於這個思路,可以考慮直接輸出文字txt
因為後期是用Excel直接檢視輸出的內容(相當於用Excel開啟txt文字),所以貌似沒出現亂碼等的問題。比較方便。
我自己實際測試過,用這個方法制作的報表匯出的文件的容量,和在Toad裡面直接匯出Excel文件的容量幾乎一樣。
注意地方:
注意的是,如果您的報表的欄位本身就包含製表符,就是說,這個欄位會被自動分行。要特別注意的。可以用RAPLACE的辦法,將欄位內容的TAB符號替代為空或者空格就行。
例子:
--XYG_XXXX公司物料編碼資訊報表
--All Inclusive GUI
PROCEDURE XYG_INV_ITEM_MSG_RPT(
X_ERR_MSG OUTVARCHAR2
,X_ERR_CODE OUTNUMBER
,P_ORGANIZATION_ID INNUMBERDEFAULT107--跑哪個組織下的所有物料。預設是主組織的
,P_ITEM_NUMBER INVARCHAR2DEFAULTNULL---物料編碼以什麼開頭(因為抓所有的太多)
,P_AUTO_MAIL_RECEIVERINVARCHAR2--發郵件通知的人,不填就是不自動發郵件。填錯當然也發不了
);
PROCEDURE XYG_INV_ITEM_MSG_RPT(
X_ERR_MSG OUTVARCHAR2
,X_ERR_CODE OUTNUMBER
,P_ORGANIZATION_ID INNUMBERDEFAULT107--跑哪個組織下的所有物料。預設是主組織的
,P_ITEM_NUMBER INVARCHAR2DEFAULTNULL---物料編碼以什麼開頭(因為抓所有的太多)
,P_AUTO_MAIL_RECEIVER INVARCHAR2--發郵件通知的人,不填就是不自動發郵件。填錯當然也發不了
)
IS
V_ORGANIZATION_CODE ORG_ORGANIZATION_DEFINITIONS.ORGANIZATION_CODE%TYPE;
V_ORGANIZATION_NAME ORG_ORGANIZATION_DEFINITIONS.ORGANIZATION_NAME%TYPE;
V_MAIL_TITLE VARCHAR2(1000);
V_MAIL_RECEIVERVARCHAR2(1000);
V_MAIL_CONTENTVARCHAR2(4000);
V_REQUEST_ID NUMBER;
V_RPT_LINK VARCHAR2(500);
V_RPT_LINK_CONTENTVARCHAR2(2000);
C_NULL CONSTANTVARCHAR2(10):=null;
CURSOR C_ALL_ITEM
IS
SELECT MSIB.ROWID ROW_ID,MSIB.SEGMENT1 ITEM_NUMBER
,MSIB.DESCRIPTION
,TO_CHAR(MSIB.CREATION_DATE,'YYYY-MM-DD HH24:MI:SS')
CREATION_DATE
,MSIB.PRIMARY_UOM_CODE
FROM MTL_SYSTEM_ITEMS_B MSIB
WHERE1=1--MSIB.ORGANIZATION_ID = OOD.ORGANIZATION_ID
AND MSIB.ENABLED_FLAG='Y'
AND MSIB.INVENTORY_ITEM_STATUS_CODE='Active'
ANDSYSDATEBETWEENNVL(TRUNC(MSIB.START_DATE_ACTIVE),SYSDATE)
ANDNVL(TRUNC(MSIB.END_DATE_ACTIVE),SYSDATE)
AND MSIB.ORGANIZATION_ID= P_ORGANIZATION_ID
AND MSIB.SEGMENT1LIKE P_ITEM_NUMBER ||'%'
ORDERBY2;
----
V_ERROR_LOG_IDNUMBER;
V_PROGRAM_POSITION XYG_PROGRAM_ERROR_LOG.PROGRAM_POSITION%TYPE;
V_ERROR_CODE XYG_PROGRAM_ERROR_LOG.ERROR_CODE%TYPE;
V_ERROR_MESSAGE XYG_PROGRAM_ERROR_LOG.ERROR_MESSAGE%TYPE;
V_USER_ID NUMBER:=FND_GLOBAL.USER_ID;
V_LOGIN NUMBER:=FND_GLOBAL.LOGIN_ID;
BEGIN
V_REQUEST_ID:=FND_GLOBAL.CONC_REQUEST_ID;
-- Output Report Head
LOG('Output Report Head');
OUTPUT ('XYG_XXXXX物料編碼資訊報表');
SELECT ORGANIZATION_CODE,ORGANIZATION_NAME
INTO V_ORGANIZATION_CODE,V_ORGANIZATION_NAME
FROM ORG_ORGANIZATION_DEFINITIONS
WHERE ORGANIZATION_ID= P_ORGANIZATION_ID;
--用CHR(9),就是TAB製表符作為欄位的分割。用Excel可以直接開啟。
OUTPUT('編碼組織:'||CHR(9)|| V_ORGANIZATION_CODE||'-'||V_ORGANIZATION_NAME);
OUTPUT ('物料編碼'||CHR(9)||'物料描述'||CHR(9)||'主單位');
FOR RECIN C_ALL_ITEMLOOP
--DBMS_OUTPUT.PUT_LINE(REC.ROW_ID);
OUTPUT(NVL(REC.ITEM_NUMBER, C_NULL)||CHR(9)||NVL(REC.DESCRIPTION, C_NULL)||CHR(9)||NVL(REC.PRIMARY_UOM_CODE, C_NULL));
--DBMS_OUTPUT.PUT_LINE(NVL (REC.ITEM_NUMBER, C_NULL)||CHR(9)||NVL (REC.DESCRIPTION, C_NULL)||CHR(9)||NVL (REC.PRIMARY_UOM_CODE, C_NULL));
--DBMS_OUTPUT.PUT_LINE(LENGTHB(NVL (REC.ITEM_NUMBER, C_NULL))||CHR(9)
--||LENGTHB(NVL (REC.DESCRIPTION, C_NULL))||CHR(9)||LENGTHB(NVL (REC.PRIMARY_UOM_CODE, C_NULL)));
ENDLOOP;
V_PROGRAM_POSITION:='END';
EXCEPTION
WHENFND_API.G_EXC_ERRORTHEN
X_ERR_CODE:=1;
LOG(X_ERR_MSG);
RAISE;
WHENOTHERSTHEN
X_ERR_CODE:=2;
X_ERR_MSG:=SQLERRM;
--NULL;
V_ERROR_CODE:=SQLCODE;
V_ERROR_MESSAGE:=SQLERRM;
LOG(SQLERRM);
RAISE;
DBMS_OUTPUT.PUT_LINE(V_ERROR_CODE ||'-' || V_ERROR_MESSAGE);
END XYG_INV_ITEM_MSG_RPT;
實際執行樣例:
報表註冊: