如何在使用 utl_file write plsql 将数据写入 .csv 文件时处理中文/日文字符

Posted

技术标签:

【中文标题】如何在使用 utl_file write plsql 将数据写入 .csv 文件时处理中文/日文字符【英文标题】:How to handle Chineese/Japenese characters while writing data to a .csv file using utl.file wirte plsql 【发布时间】:2021-04-22 10:51:14 【问题描述】:

我试图使用以下内容来处理我的数据集中的日语字符,但它似乎不起作用。

UTL_FILE.PUT_LINE(output_file1,chr(9)||CHR(15711167));

任何人都可以提出任何替代方案吗?

下面是 PL-SQL 代码。

 v_sql_stmt := 'select (dep.PEG_ITEM_NAME||''_''||substr(dep.DMD_ORG_CODE ,5)||''_''||to_char(Dep.SUP_SUGG_DUE_DATE,''ddmmyyyy'')|| ''_'' ||ind.Peg_Item_Name|| ''_'' ||substr(ind.DMD_ORG_CODE ,5)) ID,
dep.PEG_ITEM_NAME Part,
substr(dep.DMD_ORG_CODE ,5) Site,
ind.DMD_ORDER_TYPE Demand_Type,
Dep.SUP_SUGG_DUE_DATE Due_Date,
Dep.DMD_USING_REQ_QTY Demand_Qty,
ind.Peg_Item_Name Driver_Part,
substr(ind.DMD_ORG_CODE ,5) Driver_Site,
Ind.DMD_ORDER_NUMBER Sales_Order,
Ind.DMD_CUSTOMER_NAME Customer_Name
from ncr_pegging_Details dep, ncr_pegging_Details ind
where ind.batch_num=dep.batch_num 
and ind.batch_num=1846
and UPPER(dep.dmd_order_type)  in(''PLANNED ORDER DEMAND'',''WORK ORDER DEMAND'',''TRANSFER ORDER DEMAND'')
and UPPER(ind.dmd_order_type)  in(''SALES ORDER'',''FORECAST'')
and dep.PEG_END_PEGGING_ID=ind.peg_pegging_id
and ind.peg_pegging_id=ind.PEG_END_PEGGING_ID
AND substr(dep.DMD_ORG_CODE,5) in (select LOOKUP_CODE from apps.NCR_SHR_LOOKUP_VALUES@'
                      || v_db_link
                      || ' where LOOKUP_TYPE = ''NCR OCP ANP ORG LOOKUP'')
Group by (dep.PEG_ITEM_NAME||''_''||substr(dep.DMD_ORG_CODE ,5)||''_''||to_char(Dep.SUP_SUGG_DUE_DATE,''ddmmyyyy'')|| ''_'' ||ind.Peg_Item_Name|| ''_'' ||substr(ind.DMD_ORG_CODE ,5)),
dep.PEG_ITEM_NAME,substr(dep.DMD_ORG_CODE ,5),ind.DMD_ORDER_TYPE,Dep.SUP_SUGG_DUE_DATE,Dep.DMD_USING_REQ_QTY,ind.Peg_Item_Name,substr(ind.DMD_ORG_CODE ,5),
Ind.DMD_ORDER_NUMBER,Ind.DMD_CUSTOMER_NAME 
UNION 
 select (dep.PEG_ITEM_NAME||''_''||substr(dep.DMD_ORG_CODE ,5)||''_''||to_char(Dep.SUP_SUGG_DUE_DATE,''ddmmyyyy'')|| ''_'' ||ind.Peg_Item_Name|| ''_'' ||substr(ind.DMD_ORG_CODE ,5)) ID,
dep.PEG_ITEM_NAME Part,
substr(dep.DMD_ORG_CODE ,5) Site,
ind.DMD_ORDER_TYPE Demand_Type,
Dep.SUP_SUGG_DUE_DATE Due_Date,
Dep.DMD_USING_REQ_QTY Demand_Qty,
ind.Peg_Item_Name Driver_Part,
substr(ind.DMD_ORG_CODE ,5) Driver_Site,
Ind.DMD_ORDER_NUMBER Sales_Order,
Ind.DMD_CUSTOMER_NAME Customer_Name
from ncr_pegging_Details dep, ncr_pegging_Details ind
where ind.batch_num=dep.batch_num 
and ind.batch_num=1846
and UPPER(dep.dmd_order_type)  in(''PLANNED ORDER DEMAND'',''WORK ORDER DEMAND'',''TRANSFER ORDER DEMAND'')
and UPPER(ind.dmd_order_type)  in(''TRANSFER ORDER DEMAND'')
AND dep.PEG_END_PEGGING_ID=ind.PEG_END_PEGGING_ID
and dep.PEG_PREV_PEGGING_ID=ind.PEG_PEGGING_ID
AND substr(dep.DMD_ORG_CODE,5) in (select LOOKUP_CODE from apps.NCR_SHR_LOOKUP_VALUES@'
                      || v_db_link
                      || ' where LOOKUP_TYPE = ''NCR OCP ANP ORG LOOKUP'')
Group by (dep.PEG_ITEM_NAME||''_''||substr(dep.DMD_ORG_CODE ,5)||''_''||to_char(Dep.SUP_SUGG_DUE_DATE,''ddmmyyyy'')|| ''_'' ||ind.Peg_Item_Name|| ''_'' ||substr(ind.DMD_ORG_CODE ,5)),
dep.PEG_ITEM_NAME,substr(dep.DMD_ORG_CODE ,5),ind.DMD_ORDER_TYPE,Dep.SUP_SUGG_DUE_DATE,Dep.DMD_USING_REQ_QTY,ind.Peg_Item_Name,substr(ind.DMD_ORG_CODE ,5),
Ind.DMD_ORDER_NUMBER,Ind.DMD_CUSTOMER_NAME ' ;

        OPEN demand_ref_cur FOR v_sql_stmt;

        FETCH demand_ref_cur BULK COLLECT INTO demand_tbl;
        IF demand_tbl.count > 0 THEN
            v_file_name := 'AnaplanDemand.tab';
            output_file1 := utl_file.fopen('DEM_TOP_EXP_OCP', v_file_name, 'W',32700);
            UTL_FILE.PUT_LINE(output_file1,chr(9)||CHR(15711167));
            v_data := NULL;
            dbms_output.put_line('------------------------------------------------------');
            dbms_output.put_line(' File creation start.');
            dbms_output.put_line('Anaplan Report Name - ' || v_file_name);
            v_data := 'Key ID'
                      || chr(9)
                      || 'Part'
                      || chr(9)
                      || 'Site'
                      || chr(9)
                      || 'Demand Type'
                      || chr(9)
                      || 'Demand Date'
                      || chr(9)
                      || 'Qty'
                      || chr(9)
                      || 'Driver Part Name'
                      || chr(9)
                      || 'Driver Part Site'
                      || chr(9)
                      || 'Order Number'
                      || chr(9)
                      || 'Order Customer Name';

            utl_file.put_line(output_file1, v_data);
            FOR i IN demand_tbl.first..demand_tbl.last LOOP
                v_count := v_count + 1;
                v_data := demand_tbl(i).id
                          || chr(9)
                          || demand_tbl(i).part
                          || chr(9)
                          || demand_tbl(i).site
                          || chr(9)
                          || demand_tbl(i).demand_type
                          || chr(9)
                          || demand_tbl(i).due_date
                          || chr(9)
                          || demand_tbl(i).demand_qty
                          || chr(9)
                          || demand_tbl(i).driver_part
                          || chr(9)
                          || demand_tbl(i).driver_site
                          || chr(9)
                          || demand_tbl(i).sales_order
                          || chr(9)
                          || demand_tbl(i).customer_name;

                utl_file.put_line(output_file1, v_data);
                v_data := NULL;
            END LOOP;

            dbms_output.put_line('Total Records written in file is ' || v_count);
            utl_file.fclose(output_file1);
        END IF;
    END ncr_ocp_anp_demand_extract_proc;

附件是输出文件。请看一下,如果还需要什么,请告诉我。

Output file ss

【问题讨论】:

“它似乎工作” - 没有足够的信息.. 你使用utl_file.fopen_nchar 还是只使用fopen 你期待哪个角色?字符 15711167 => EFBBBF 不存在。 UTF-8 字节值是U+FEFF, BYTE ORDER MARK。这应该是文档中的第一个字符。 我只使用 fopen。但在输出文件中,我在列客户名称中看到以下字符,我在某些字段中得到以下字符。 ×∼×™×' ×∼×¢× ×¨×©×ª×•×ª ×'×¢"מ ×—×'×™×' ×'×¢×™ ר ×'×¢"מ דור ×לון ×ž×ª×—×ž×™× ×§×ž×¢×•× ××™×™× ×” ×•× ×¡× ×∼ר (עשה ×–×ת ×'עצמך) ×'×¢"מ ×∼×™×' ×∼×¢ × ×¨×©×ª×•×ª ×'×¢"מ ×—×'×™×' ×'עיר ×'×¢"מ דור ×ל ון ×ž×ª×—×ž×™× ×§×ž×¢×•× ××™×™× 嗨@SayanMalakshinov 我只使用fopen。请分享一份关于使用 fope_nchar 的文档。还有这两者有什么不同? 【参考方案1】:

不清楚你在找什么。

CHR(15711167 USING NCHAR_CS)

返回 "뮿" -> U+BBBF: Hangul Syllable Myuh

15711167 十进制是EFBBBF hex,看起来CHR(... USING NCHAR_CS) 忽略了第一个字节,因为它需要偶数个字节。

所以,CHR(48063 USING NCHAR_CS) 给出相同的值,因为 48063 十进制是 BBBF 十六进制。

如果您知道 Unicode 代码点,您也可以使用

UTL_I18N.RAW_TO_CHAR(HEXTORAW(TO_CHAR('BBBF', 'fmXXXX')), 'AL16UTF16')

注意,这仅适用于Basic Multilingual Plane。如果您想测试完整的 Unicode 范围,可以使用这些函数。

-- Similar to Oracle function CHR/NCHR but accept supplementary characters above 65535 (U+FFFF) without transformation to UCS-2
CREATE OR REPLACE FUNCTION CHRF(codepoint INTEGER) RETURN VARCHAR2 DETERMINISTIC IS
    sg1 VARCHAR2(4);
    sg2 VARCHAR2(4);
BEGIN
    IF codepoint <= 65535 THEN
        RETURN UTL_I18N.RAW_TO_CHAR(HEXTORAW(TO_CHAR(codepoint, 'fmXXXX')), 'AL16UTF16');
    ELSE
        sg1 := LPAD(TO_CHAR(TO_NUMBER('D800', 'XXXX') + TRUNC((codepoint - 2**16) / 2**10), 'fmXXXX'), 4, '0');
        sg2 := LPAD(TO_CHAR(TO_NUMBER('DC00', 'XXXX') + (codepoint - 2**16) MOD 2**10, 'fmXXXX'), 4, '0');
        RETURN UTL_I18N.RAW_TO_CHAR(HEXTORAW(sg1||sg2), 'AL16UTF16');
    END IF; 
END CHRF;


-- Similar to Oracle function UNISTR but accept supplementary characters above U+FFFF without transformation to UCS-2.
-- Unlike UNISTR this function supports only one single character
CREATE OR REPLACE FUNCTION UNISTRF(codepoint VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
    RETURN CHRF(TO_NUMBER(REGEXP_SUBSTR(codepoint, '[[:xdigit:]]1,6$'), 'XXXXXX'));
END UNISTRF;

【讨论】:

以上是关于如何在使用 utl_file write plsql 将数据写入 .csv 文件时处理中文/日文字符的主要内容,如果未能解决你的问题,请参考以下文章

如何在 oracle 中使用 utl_file 写入文件

如何在 UTL_FILE 过程中包含一个巨大的 SQL 语句?

PL/SQL UTL_FILE:循环如何自动返回下一行?

计算由 UTL_FILE 创建的文件中的行数

使用 UTL_FILE 脚本损坏文件

UTL_FILE