全部產品
Search
文件中心

MaxCompute:CSV/TSV外部表格

更新時間:Jan 28, 2026

本文介紹CSV、TSV格式的OSS外部表格的建立、讀取及寫入方法。

適用範圍

  • OSS外部表格不支援cluster屬性。

  • 單個檔案大小不能超過2GB,如果檔案過大,建議拆分。

  • MaxCompute需要與OSS部署在同一地區。

支援資料類型

MaxCompute資料類型詳情請參見1.0資料類型版本2.0資料類型版本

更多有關SmartParse的說明,請參見Smart Parse更靈活的類型相容能力

資料類型

com.aliyun.odps.CsvStorageHandler/

TsvStorageHandler

(內建文本資料解析器)

org.apache.hadoop.hive.serde2.OpenCSVSerde

(內建開來源資料解析器)

TINYINT

支援

支援

SMALLINT

支援

支援

INT

支援

支援

BIGINT

支援

支援

BINARY

不支援

不支援

FLOAT

支援

支援

DOUBLE

支援

支援

DECIMAL(precision,scale)

支援

支援

VARCHAR(n)

支援

支援

CHAR(n)

支援

支援

STRING

支援

支援

DATE

支援

支援

DATETIME

支援

支援

TIMESTAMP

支援

支援

TIMESTAMP_NTZ

支援

不支援

BOOLEAN

支援

支援

ARRAY

不支援

不支援

MAP

不支援

不支援

STRUCT

不支援

不支援

JSON

不支援

不支援

支援壓縮格式

當讀寫壓縮屬性的OSS檔案時,需要在建表語句中添加with serdeproperties屬性配置,詳情請參見with serdeproperties屬性參數

壓縮格式

com.aliyun.odps.CsvStorageHandler/

TsvStorageHandler

(內建文本資料解析器)

org.apache.hadoop.hive.serde2.OpenCSVSerde

(內建開來源資料解析器)

GZIP

支援

支援

SNAPPY

不支援

支援

LZO

不支援

支援

支援Schema Evolution

操作類型

是否支援

說明

添加列

支援

  • 不支援添加設定預設值的列。

  • 不支援添加複雜類型列、嵌套列。

刪除列

支援

不建議使用,會出現Schema和資料不對應的問題。

修改列順序

支援

不建議使用,會出現Schema和資料不對應的問題。

更改列資料類型

支援

資料類型支援轉換表見更改列資料類型

修改列名

支援

修改列注釋

支援

注釋內容為長度不超過1024位元組的有效字串,否則報錯。

修改列的非空屬性

不支援

不支援此操作,預設為Nullable。

參數配置

CSV和TSV外表的Schema和檔案列之間按位置映射。當讀取的OSS檔案的檔案列數和外部表格的Schema列不一致時,可通過odps.sql.text.schema.mismatch.mode參數指定對於列數不一致行的處理方式。

  • odps.sql.text.schema.mismatch.mode=truncate時,修改列操作後

    • 符合修改後的Schema結構的資料,可以正常讀取;

    • 存量舊Schema資料沒有進行修改列操作,該表按新Schema讀。

      例如,表添加列後,歷史資料沒有添加對應列,讀表時該列的歷史資料會補為NULL。

  • odps.sql.text.schema.mismatch.mode=ignore時,修改列操作後

    • 符合修改後的Schema結構的資料,可以正常讀取;

    • 存量舊Schema資料沒有進行修改列操作,該表按新Schema讀。

      例如,表添加列後,歷史資料沒有添加對應列,讀表時會把歷史資料整行丟棄。

  • odps.sql.text.schema.mismatch.mode=error時,修改列操作後

    • 符合修改後的Schema結構的資料,可以正常讀取;

    • 存量舊Schema資料沒有進行修改列操作,該表按新Schema讀。

      例如,表添加列後,歷史資料沒有添加對應列,讀表時會報錯。

建立外部表格

文法結構

內建文本資料解析器

CSV格式

CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name> 
(
  <col_name> <data_type>,
  ...
)
[COMMENT <table_comment>]
[PARTITIONED BY (<col_name> <data_type>, ...)] 
STORED BY 'com.aliyun.odps.CsvStorageHandler'  
[WITH serdeproperties (
  ['<property_name>'='<property_value>',...]
)] 
LOCATION '<oss_location>'
[tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];

TSV格式

CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name> 
(
  <col_name> <data_type>,
  ...
)
[COMMENT <table_comment>]
[PARTITIONED BY (<col_name> <data_type>, ...)] 
STORED BY 'com.aliyun.odps.TsvStorageHandler'  
[WITH serdeproperties (
  ['<property_name>'='<property_value>',...]
)] 
LOCATION '<oss_location>'
[tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];

內建開來源資料解析器

CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name>
(
  <col_name> <data_type>,
  ...
)
[COMMENT <table_comment>]
[PARTITIONED BY (<col_name> <data_type>, ...)]
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
[WITH serdeproperties (
  ['<property_name>'='<property_value>',...]
)]
STORED AS TEXTFILE 
LOCATION '<oss_location>' 
[tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];

公用參數

公用參數說明請參見基礎文法參數說明

專屬參數

with serdeproperties屬性參數

適用解析器

property_name

使用情境

說明

property_value

預設值

內建文本資料解析器(CsvStorageHandler/TsvStorageHandler)

odps.text.option.gzip.input.enabled

當需要讀取以GZIP方式壓縮的CSV或TSV檔案資料時,請添加該屬性。

CSV、TSV壓縮屬性。配置該參數值為True時,MaxCompute才可以正常讀取壓縮檔,否則會讀取失敗。

  • True

  • False

False

odps.text.option.gzip.output.enabled

當需要將資料以GZIP壓縮方式寫入OSS時,請添加該屬性。

CSV、TSV壓縮屬性。配置該參數值為True時,MaxCompute才能將資料以GZIP壓縮方式寫入OSS,否則不壓縮。

  • True

  • False

False

odps.text.option.header.lines.count

當OSS資料檔案為CSV或TSV,且需要忽略OSS資料檔案中的前N行時,請添加該屬性。

MaxCompute讀取OSS資料檔案時,會忽略指定的行數。

非負整數

0

odps.text.option.null.indicator

當OSS資料檔案為CSV或TSV,且需要定義OSS資料檔案中NULL的解析規則時,請添加該屬性。

通過該參數配置的字串會被解析為SQL中的NULL。

例如將檔案中\N解析為NULL,需要配置此參數為\\N,其中第一個\為轉義符。則a,\N,b會解析為a, NULL, b

字串

Null 字元串

odps.text.option.ignore.empty.lines

當OSS資料檔案為CSV或TSV,且需要定義OSS資料檔案中空行的處理規則時,請添加該屬性。

配置該參數值為True時,MaxCompute會忽略資料檔案中的空行,否則會讀取空行。

  • True

  • False

True

odps.text.option.encoding

當OSS資料檔案為CSV或TSV,且OSS資料檔案編碼規則非預設編碼規則時,請添加該屬性。

確保此處配置的編碼規則與OSS資料檔案編碼規則保持一致,否則MaxCompute無法成功讀取資料。

  • UTF-8

  • UTF-16

  • US-ASCII

  • GBK

UTF-8

odps.text.option.delimiter

當需要明確CSV或TSV資料檔案的資料行分隔符號時,請添加該屬性。

確保此處配置的資料行分隔符號可以正確讀取OSS資料檔案的每一列,否則MaxCompute讀取的資料會出現錯位問題。

單個字元

半形逗號(,)

odps.text.option.use.quote

當CSV或TSV資料檔案中的欄位包含換行(CRLF)、雙引號或英文逗號時,請添加該屬性。

當CSV某個欄位中包含換行、雙引號(需要在"前再加"轉義)或英文逗號時,整個欄位必須用雙引號("")括起來作為資料行分隔符號。該參數指定是否識別CSV的資料行分隔符號"

  • True

  • False

False

odps.sql.text.option.flush.header

在往OSS寫資料的時候,檔案塊的第一行為表頭。

只有針對CSV檔案格式生效。

  • True

  • False

False

odps.sql.text.schema.mismatch.mode

當讀取的OSS檔案的資料列數和外部表格的Schema列數不一致時。

指定對於列數不一致行的處理方式。

說明:odps.text.option.use.quote參數值為True時,該功能不生效。

  • error:報錯。

  • truncate:超過外部表格列數部分資料被丟棄;少於外部表格列數部分資料則補null

  • ignore:丟棄不一致的行。

error

內建開來源資料解析器(OpenCSVSerde)

separatorChar

當需要明確以TEXTFILE格式儲存的CSV資料的資料行分隔符號時,請添加該屬性。

指定CSV資料資料行分隔符號。

單個字串

半形逗號(,)

quoteChar

當以TEXTFILE格式儲存的CSV資料中的欄位包含換行、雙引號或英文逗號時,請添加該屬性。

指定CSV資料的引用符。

單個字串

escapeChar

當需要明確以TEXTFILE格式儲存的CSV資料的轉義規則時,請添加該屬性。

指定CSV資料的轉義符。

單個字串

tblproperties屬性參數

適用解析器

property_name

使用情境

說明

property_value

預設值

內建開來源資料解析器(OpenCSVSerde)

skip.header.line.count

當需要忽略以TEXTFILE格式儲存的CSV檔案中的前N行資料時,請添加該屬性。

MaxCompute讀取OSS資料時,會忽略從首行開始指定行數的資料。

非負整數

skip.footer.line.count

當需要忽略以TEXTFILE格式儲存的CSV檔案中的後N行資料時,請添加該屬性。

MaxCompute讀取OSS資料時,會忽略從尾行開始指定行數的資料。

非負整數

mcfed.mapreduce.output.fileoutputformat.compress

當需要將TEXTFILE資料檔案以壓縮方式寫入OSS時,請添加該屬性。

TEXTFILE壓縮屬性。配置該參數值為True時,MaxCompute才可以將TEXTFILE資料檔案以壓縮方式寫入OSS,否則不壓縮。

  • True

  • False

False

mcfed.mapreduce.output.fileoutputformat.compress.codec

當需要將TEXTFILE資料檔案以壓縮方式寫入OSS時,請添加該屬性。

TEXTFILE壓縮屬性。設定TEXTFILE資料檔案的壓縮方式。

說明:只支援property_value中的四種壓縮方式。

  • com.hadoop.compression.lzo.LzoCodec

  • com.hadoop.compression.lzo.LzopCodec

  • org.apache.hadoop.io.compress.SnappyCodec

  • com.aliyun.odps.io.compress.SnappyRawCodec

io.compression.codecs

當OSS資料檔案為Raw-Snappy格式時,請添加該屬性。

配置該參數值為True時,MaxCompute才可以正常讀取壓縮資料,否則MaxCompute無法成功讀取資料。

com.aliyun.odps.io.compress.SnappyRawCodec

odps.text.option.bad.row.skipping

當OSS資料檔案為CSV時,且需要跳過OSS資料檔案中的髒資料時,請添加該屬性。

MaxCompute讀取OSS資料檔案時,可以選擇跳過或者不跳過髒資料。

  • rigid:一定會執行跳過邏輯,不能被session/project層面的配置覆蓋。

  • flexible:資料層面開啟彈性跳過,但也可以被session/project層面的配置覆蓋。

寫入資料

MaxCompute寫入文法詳情,請參見寫入文法說明

查詢分析

BadRowSkipping

當CSV資料中出現髒資料時,可以通過BadRowSkipping功能,設定參數選擇跳過或者不跳過報錯資料。參數開啟與否,不影響理解底層資料格式。

參數配置

  • 表層級參數odps.text.option.bad.row.skipping

    • rigid:一定要執行跳過邏輯,不能被session/project層面的配置覆蓋。

    • flexible:資料層面開啟彈性跳過,但也可以被session/project層面的配置覆蓋。

  • session/project層級參數

    • odps.sql.unstructured.text.bad.row.skipping,可以覆蓋flexible表參數,但不能覆蓋rigid表參數。

      • on主動開啟,如果表上未配置,自動開啟。

      • off主動關閉,如果表上配置成flexible,會執行主動關閉,其他情況以表參數為準。

      • <null>/輸入不合法時:只看錶層級配置行為。

    • odps.sql.unstructured.text.bad.row.skipping.debug.num,表示允許列印出錯結果到Logview的Stdout中的條數。

      • 最大值只能為1000

      • 值<=0時,表示關閉

      • 輸入不合法時,表示關閉

  • Session層級參數和表層面參數互動關係

    tbl property

    session flag

    result

    rigid

    on

    開,強制開啟

    off

    <null>,或者不合法的值,或者不配置該參數值

    flexible

    on

    off

    關,被session關閉

    <null>,或者不合法的值,或者不配置該參數值

    沒有配置

    on

    開,session開啟

    off

    <null>,或者不合法的值,或者不配置該參數值

使用樣本

  1. 資料準備

    將存在部分髒資料的測試資料csv_bad_row_skipping.csv上傳至OSSoss-mc-test/badrow/

  2. 建立CSV外部表格

    表層級參數和session層級flag不一樣,三種情況如下所示。

    • 表參數: odps.text.option.bad.row.skipping = flexible/rigid/<不填>

    • session flag: odps.sql.unstructured.text.bad.row.skipping = on/off/<不填>

    表層級沒有配置參數

    -- 表層級沒有配置參數,該報錯就報錯,靠session層級flag來控制
    CREATE EXTERNAL TABLE test_csv_bad_data_skipping_flag
    (
      a INT,
      b INT
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole'
    )
    location '<oss://databucketpath>';

    表層級參數跳過錯誤行,Session層級可以關閉

    -- 表層級參數跳過錯誤行,不過session層級的flag可以主動關閉
    CREATE EXTERNAL TABLE test_csv_bad_data_skipping_flexible
    (
      a INT,
      b INT
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole'
    )
    location '<oss://databucketpath>'
    tblproperties (
      'odps.text.option.bad.row.skipping' = 'flexible'   -- 彈性開啟,session層級可關閉
    );

    表層級參數跳過錯誤行,Session層級無法關閉

    -- 表層級參數強制開啟跳過錯誤,session層級無法關閉
    CREATE EXTERNAL TABLE test_csv_bad_data_skipping_rigid
    (
      a INT,
      b INT
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole'
    )
    location '<oss://databucketpath>'
    tblproperties (
      'odps.text.option.bad.row.skipping' = 'rigid'  -- 強制開啟
    );
  3. 驗證查詢結果

    表層級沒有配置參數

    -- session層級開啟
    SET odps.sql.unstructured.text.bad.row.skipping=on;
    
    -- session層級關閉,如果表層級配置為'flexible',則會被關閉,如果表層級配置'rigid'則不受影響;
    SET odps.sql.unstructured.text.bad.row.skipping=off;
    
    -- session層級列印有問題的行資料,最大1000條,小於等於0時,就關閉了錯誤資料列印
    SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10;
    
    SELECT * FROM test_csv_bad_data_skipping_flag;

    返回報錯:FAILED: ODPS-0123131:User defined function exception

    表層級參數跳過錯誤行,Session層級可以關閉

    -- session層級開啟
    SET odps.sql.unstructured.text.bad.row.skipping=on;
    
    -- session層級關閉,如果表層級配置為'flexible',則會被關閉,如果表層級配置'rigid'則不受影響;
    SET odps.sql.unstructured.text.bad.row.skipping=off;
    
    -- session層級列印有問題的行資料,最大1000條,小於等於0時,就關閉了錯誤資料列印
    SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10;
    
    SELECT * FROM test_csv_bad_data_skipping_flexible;

    返回報錯:FAILED: ODPS-0123131:User defined function exception

    表層級參數跳過錯誤行,Session層級無法關閉

    -- session層級開啟
    SET odps.sql.unstructured.text.bad.row.skipping=on;
    
    -- session層級關閉,如果表層級配置為'flexible',則會被關閉,如果表層級配置'rigid'則不受影響;
    SET odps.sql.unstructured.text.bad.row.skipping=off;
    
    -- session層級列印有問題的行資料,最大1000條,小於等於0時,就關閉了錯誤資料列印
    SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10;
    
    SELECT * FROM test_csv_bad_data_skipping_rigid;

    返回結果如下:

    +------------+------------+
    | a          | b          | 
    +------------+------------+
    | 1          | 26         | 
    | 5          | 37         | 
    +------------+------------+

Smart Parse更靈活的類型相容能力

針對CSV格式的OSS外部表格,MaxCompute SQL採用2.0資料類型進行讀寫,之前僅支援部分嚴格格式的值,並按照相應的資料類型進行讀寫。現已相容讀取CSV中各種類型的值。具體如下:

Type

Input as String

Output as String

Description

BOOLEAN

  • "true"/"false"

  • "T"/"F"

  • "1"/"0"

  • "Yes"/"No"

  • "Y"/"N"

  • ""(空串讀進表中會被解析為NULL)

說明

解析時會對輸入執行trim()操作。

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • ""(NULL被輸出至CSV中為空白串)

不在枚舉值範圍,則解析失敗。

TINYINT

  • "0"

  • "1"

  • "-100"

  • "1,234,567"(千分位標記法,逗號不能作為該數字串的首尾字元)

  • "1_234_567"(Java-style,底線不能作為該數字串的首尾字元)

  • "0.3e2"(科學計數法,其表示的實際數值為整數時可被解析,否則會報錯)

  • "-1e5"(科學計數法)

  • "0xff"(十六進位,大小寫不敏感)

  • "0b1001"(二進位,大小寫不敏感)

  • "4/2"(分數,其表示的實際數值為整數時可被解析,否則會報錯)

  • "1000%"(百分數,其表示的實際數值為整數時可被解析,否則會報錯)

  • "1000‰"(千分數,其表示的實際數值為整數時可被解析,否則會報錯)

  • "1,000 $"(帶貨幣符號)

  • "$ 1,000"(帶貨幣符號)

  • "3M"(K8s-style, 1000進位單位)

  • "2Gi"(K8s-style, 1024進位單位)

  • ""(空串讀進表中會被解析為NULL)

說明
  • 解析時會對輸入執行trim()操作。

  • 如果使用千分位標記法,例如"1,234,567" ,則需要手動設定CSV分隔字元為非英文逗號的其他符號。具體請參見with serdeproperties屬性參數odps.text.option.delimiter的用法。

  • K8s-style支援的1000進位單位包括 K/M/G/P/T,1024進位單位包括 Ki/Mi/Gi/Pi/Ti,詳情請參見resource-management

  • 貨幣符號包括$/¥/€/£/₩/USD/CNY/EUR/GBP/JPY/KRW/IDR/RP

  • "0""1""-100"""在naive模式下也可以被正確解析。

  • "0"

  • "1"

  • "-100"

  • "1234567"

  • "1234567"

  • "30"

  • "-100000"

  • "255"

  • "9"

  • "2"

  • "10"

  • "1"

  • "1000"

  • "1000"

  • "3000000"(1M=1000*1000)

  • "2147483648"(1 Gi=1024*1024*1024)

  • ""(NULL被輸出至CSV中為空白串)

8位整型,超出範圍範圍[-128, 127]則報錯。

SMALLINT

16位整型,超出範圍範圍[-32768, 32767]則報錯。

INT

32位整型,超出範圍範圍[-2147483648, 2147483647]則報錯。

BIGINT

64位整型,超出範圍範圍[-9223372036854775807, 9223372036854775807]則報錯。

說明

-263(即-9223372036854775808)不在範圍範圍內,為SQL引擎的限制。

FLOAT

  • "3.14"

  • "0.314e1"(科學計數法)

  • "2/5"(分數)

  • "123.45%"(百分數)

  • "123.45‰"(千分數)

  • "1,234,567.89"(千分位表示)

  • "1,234.56 $"(帶貨幣符號)

  • "$ 1,234.56"(帶貨幣符號)

  • "1.2M"(K8s-style,1000進位單位)

  • "2Gi"(K8s-style,1024進位單位)

  • "NaN"(大小寫不敏感)

  • "Inf"(大小寫不敏感)

  • "-Inf"(大小寫不敏感)

  • "Infinity"(大小寫不敏感)

  • "-Infinity"(大小寫不敏感)

  • ""(空串讀進表中會被解析為NULL)

說明
  • 解析時會對輸入執行trim()操作。

  • "3.14""0.314e1""NaN""Infinity""-Infinity"""在naive模式下也可以被正確解析。

  • "3.14"

  • "3.14"

  • "0.4"

  • "1.2345"

  • "0.12345"

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • "NaN"

  • "Infinity"

  • "-Infinity"

  • "Infinity"

  • "-Infinity"

  • ""(null被輸出至csv中為空白串)

特殊值(大小寫不敏感)包括:NaN、Inf、-Inf、Intifniy和-Intifniy。在超出範圍範圍時,將報錯;若精度超出,則進行四捨五入截斷。

DOUBLE

  • "3.1415926"

  • "0.314e1"(科學計數法)

  • "2/5"(分數)

  • "123.45%"(百分數)

  • "123.45‰"(千分數)

  • "1,234,567.89"(千分位表示)

  • "1,234.56 $"(帶貨幣符號)

  • "$ 1,234.56"(帶貨幣符號)

  • "1.2M"(K8s-style,1000進位單位)

  • "2Gi"(K8s-style,1024進位單位)

  • "NaN"(大小寫不敏感)

  • "Inf"(大小寫不敏感)

  • "-Inf"(大小寫不敏感)

  • "Infinity"(大小寫不敏感)

  • "-Infinity"(大小寫不敏感)

  • ""(空串讀進表中會被解析為NULL)

說明
  • 解析時會對輸入執行trim()操作。

  • "3.1415926""0.314e1""NaN""Infinity""-Infinity"""在naive模式下也可以被正確解析。

  • "3.1415926"

  • "3.14"

  • "0.4"

  • "1.2345"

  • "0.12345"

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • "NaN"

  • "Infinity"

  • "-Infinity"

  • "Infinity"

  • "-Infinity"

  • ""(NULL被輸出至CSV中為空白串)

特殊值(大小寫不敏感)包括:NaN、Inf、-Inf、Intifniy和-Intifniy。在超出範圍範圍時,將報錯;若精度超出,則進行四捨五入截斷。

DECIMAL

(precision, scale)

以DECIMAL(15,2)為例

  • "3.358"

  • "2/5"(分數)

  • "123.45%"(百分數)

  • "123.45‰"(千分數)

  • "1,234,567.89"(千分位表示)

  • "1,234.56 $"(帶貨幣符號)

  • "$ 1,234.56"(帶貨幣符號)

  • "1.2M"(K8s-style, 1000進位單位)

  • "2Gi"(K8s-style, 1024進位單位)

  • ""(空串讀進表中會被解析為NULL)

說明
  • 解析時會對輸入執行trim()操作。

  • "3.358"""在naive模式下也可以被正確解析。

  • "3.36"(四捨五入)

  • "0.4"

  • "1.23"(四捨五入)

  • "0.12"(四捨五入)

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • ""(NULL被輸出至CSV中為空白串)

整數部分值超出precision-scale

則會報錯;小數部分超出scale,則會進行四捨五入截斷。

CHAR(n)

以CHAR(7)為例

  • "abcdefg"

  • "abcdefghijklmn"

  • "abc"

  • ""(空串讀進表中會被解析為NULL)

  • "abcdefg"

  • "abcdefg"(後續部分被截斷)

  • "abc____"(_表示空格,擴充了4個Null 字元)

  • ""(NULL被輸出至CSV中為空白串)

最大長度為255。長度不足則會填充空格,但空格不參與比較。長度超出n會截斷。

VARCHAR(n)

以VARCHAR(7)為例

  • "abcdefg"

  • "abcdefghijklmn"

  • "abc"

  • ""(空串讀進表中會被解析為NULL)

  • "abcdefg"

  • "abcdefg"(後續部分被截斷)

  • "abc"

  • ""(NULL被輸出至CSV中為空白串)

最大長度為65535。長度超出n會截斷。

STRING

  • "abcdefg"

  • "abc"

  • ""(空串讀進表中會被解析為NULL)

  • "abcdefg"

  • "abc"

  • ""(NULL被輸出至CSV中為空白串)

長度限制為8 MB。

DATE

  • "yyyy-MM-dd"(例如"2025-02-21")

  • "yyyyMMdd"(例如"20250221")

  • "MMM d,yyyy"(例如"October 1,2025")

  • "MMMM d,yyyy"(例如"Oct 1,2025")

  • "yyyy年M月d日"(例如"2025年10月1日")

  • ""(空串讀進表中會被解析為NULL)

說明

您也可以通過自訂odps.text.option.date.io.format控制讀入時的解析方式。例如使用者定義format為 'dd/MM/yyyy#yyyy--MM--dd',則可以解析'21/02/2025''2025--02--21'

  • "2000-01-01"

  • "2000-01-01"

  • ""(NULL被輸出至CSV中為空白串)

  • 無時分秒資訊,改變時區不影響輸出結果。預設輸出格式為"yyyy-MM-dd"

  • 您也可以通過自訂odps.text.option.date.io.format 來控制解析與輸出格式。輸出格式將採用自訂的首個pattern。格式可參考DateTimeFormatter

TIMESTAMP_NTZ

說明

OpenCsvSerde不支援此類型,因為該類型與Hive資料格式不相容。

  • 納秒位長度可為0~9,MaxCompute支援的內建解析格式如下:

    • "yyyy-MM-dd HH:mm:ss[.SSSSSSSSS]"(例如"2000-01-01 00:00:00.123")

    • "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS]"(例如"2000-01-01T00:00:00.123456789")

    • "yyyyMMddHHmmss"(例如"20000101000000")

    • ""(空串讀進表中會被解析為NULL)

  • 您也可通過自訂odps.text.option.timestamp_ntz.io.format來控制讀入時的解析方式。例如使用者定義format為'ddMMyyyy-HHmmss',則可以解析形如'31102024-103055'的字串。

  • "2000-01-01 00:00:00.123000000"

  • "2000-01-01 00:00:00.123456789"

  • "2000-01-01 00:00:00.000000000"

  • ""(NULL被輸出至CSV中為空白串)

  • 本質為納秒粒度的時間戳記,改變時區資訊不影響輸出結果,即預設使用標準UTC時區輸出結果。預設輸出格式為"yyyy-MM-dd HH:mm:ss.SSSSSSSSS"

  • 您也可以通過自訂odps.text.option.timestamp_ntz.io.format控制解析與輸出格式。格式可參考DateTimeFormatter

DATETIME

  • 毫秒位長度可為0~3,x表示時區位移,假設系統時區為Asia/Shanghai,MaxCompute支援的內建解析格式如下:

    • "yyyy-MM-dd HH:mm:ss[.SSS][x]"(例如"2000-01-01 00:00:00.123")

    • "yyyy-MM-ddTHH:mm:ss[.SSS][x]"(例如"2000-01-01T00:00:00.123+0000")

    • "yyyyMMddHHmmss[x]" (例如"20000101000000+0000")

    • ""(空串讀進表中會被解析為NULL)

  • 您也可通過自訂odps.text.option.datetime.io.format來控制讀入時的解析方式。例如使用者定義format為 'yyyyMMdd-HHmmss.SSS',則可以解析形如'20241031-103055.123'的字串。

假設系統時區為Asia/Shanghai:

  • "2000-01-01 00:00:00.123+0800"

  • "2000-01-01 08:00:00.123+0800"

  • "2000-01-01 08:00:00.000+0800"

  • ""(NULL被輸出至CSV中為空白串)

  • 本質為毫秒粒度的時間戳記,改變時區資訊影響輸出結果。預設輸出格式為"yyyy-MM-dd HH:mm:ss.SSSx"

  • 您可通過odps.sql.timezone修改系統時區,從而控制寫出值的時區位移。

  • 您也可通過自訂odps.text.option.datetime.io.format控制解析與輸出格式。格式可參考:DateTimeFormatter

TIMESTAMP

  • 納秒位長度可為0~9,x表示時區位移,假設系統時區為Asia/Shanghai,MaxCompute支援的內建解析格式:

    • "yyyy-MM-dd HH:mm:ss[.SSSSSSSSS][x]"(例如"2000-01-01 00:00:00.123456")

    • "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS][x]"(例如"2000-01-01T00:00:00.123+0000")

    • "yyyyMMddHHmmss[x]"(例如"20000101000000+0000")

    • ""(空串讀進表中會被解析為NULL)

  • 您也可通過自訂odps.text.option.timestamp.io.format來控制讀入時的解析方式。例如使用者定義format為'yyyyMMdd-HHmmss',則可以解析形如'20240910-103055'的字串。

(假設系統時區為Asia/Shanghai)

  • "2000-01-01 00:00:00.123456000+0800"

  • "2000-01-01 08:00:00.123000000+0800"

  • "2000-01-01 08:00:00.000000000+0800"

  • ""(NULL被輸出至CSV中為空白串)

  • 本質為納秒粒度的時間戳記,改變時區資訊影響輸出結果。預設輸出格式為"yyyy-MM-dd HH:mm:ss.SSSSSSSSSx"

  • 您可通過odps.sql.timezone修改系統時區,從而控制寫出值的時區位移。

  • 您也可通過自訂odps.text.option.timestamp.io.format控制解析與輸出格式。格式可參考DateTimeFormatter

  • 通用規則

    • 對於任意類型,CSV資料檔案中的Null 字元串被讀入表中後,均會被解析為NULL。

  • 不支援的資料類型

    • 複雜類型 (STRUCT/ARRAY/MAP):不支援。因為這些複雜類型的值很容易和CSV的常見分隔字元(,)發生衝突導致解析失敗。

    • BINARY/INTERVAL 類型:暫不支援。如有需求請聯絡MaxCompute支援人員。

  • 數實值型別 (INT、DOUBLE等)

    • 對於資料類型INT/SMALLINT/TINYINT/BIGINT/FLOAT/DOUBLE/DECIMAL,預設的解析能力(DEFAULT)比較豐富。

    • 如果只想解析基礎的數字串,可以在tblproperties中將odps.text.option.smart.parse.level參數設定為naive,使解析器僅支援解析普通數字串,例如“123”、“123.456”,其他形態的字串在解析時會報錯。

  • 日期與時間類型 (DATE, TIMESTAMP等)

    • 對於四種日期或時間相互關聯類型 DATA/DATETIME/TIMESTAMP/TIMESTAMP_NTZ,在底層代碼中均使用 java.time.format.DateTimeFormatter 處理。

    • 預設格式:MaxCompute內建了若干的預設解析格式。

    • 自訂格式:

      • 通過在 tblproperties 中設定 odps.text.option.<date|datetime|timestamp|timestamp_ntz>.io.format 來自訂多種解析格式與一種輸出格式。

      • 多個解析格式之間用 # 分隔。

      • 自訂格式的優先順序高於MaxCompute的內建解析格式,輸出格式將採用第一個自訂格式。

      • 樣本:若自訂DATE類型的格式串為pattern1#pattern2#pattern3,則可以解析符合pattern1pattern2pattern3的字串,但輸出至檔案時會採用pattern1格式來輸出。詳情請參見DateTimeFormatter

  • 重要提醒:關於時區格式z的說明

    • 不建議使用 'z' (time-zone name) 作為自訂的時區格式(尤其對於中國區使用者),因為 'z' 在某些上下文中可能存在歧義。

    • 建議改用 'x' (zone-offset) 或 'VV' (time-zone ID) 作為時區模式。

    • 樣本:'CST' 在中國語境下通常表示中國標準時間(UTC+8),然而當 'CST' 被java.time.format.DateTimeFormatter解析時,會被識別為美國中部標準時間(UTC-6),這可能導致非預期的輸入或輸出結果。

使用樣本

前置準備

  • 建立MaxCompute專案

  • 已準備好OSS儲存空間(Bucket)、OSS目錄。具體操作請參見建立儲存空間管理目錄

    MaxCompute已支援在OSS側自動建立目錄,對於攜帶外部表格及UDF的SQL語句,可以通過一條SQL語句執行讀寫外部表格及UDF的操作。原手動建立目錄方式仍然支援。

    由於MaxCompute只在部分地區部署,跨地區的資料連通性可能存在問題,因此建議Bucket與MaxCompute專案所在地區保持一致。
  • 授權

    • 已具備訪問OSS的許可權。阿里雲帳號(主帳號)、RAM使用者或RAMRole身份可以訪問OSS外部表格,授權資訊請參見OSS的STS模式授權

    • 已具備在MaxCompute專案中建立表(CreateTable)的許可權。表操作的許可權資訊請參見MaxCompute許可權

通過內建文本資料解析器建立OSS外部表格

樣本一:非分區表

  1. 樣本資料中的Demo1/目錄建立映射關係。建立OSS外部表格的命令樣本如下。

    CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external1
    (
      vehicleId INT,
      recordId INT,
      patientId INT,
      calls INT,
      locationLatitute DOUBLE,
      locationLongtitue DOUBLE,
      recordTime STRING,
      direction STRING
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole'
    ) 
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo1/';
    
    -- 可以執行desc extended mc_oss_csv_external1;命令查看建立好的OSS外部表格結構資訊。

    樣本中使用的角色為aliyunodpsdefaultrole,如果使用其他角色,需要將aliyunodpsdefaultrole替換為目標角色名稱,並為目標角色授予訪問OSS的許可權。

  2. 查詢非分區外表。

    SELECT * FROM mc_oss_csv_external1;

    返回結果如下:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 1          | 1          | 51         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | S          |
    | 1          | 2          | 13         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         |
    | 1          | 3          | 48         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         |
    | 1          | 4          | 30         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | W          |
    | 1          | 5          | 47         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | S          |
    | 1          | 6          | 9          | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | S          |
    | 1          | 7          | 53         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | N          |
    | 1          | 8          | 63         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | SW         |
    | 1          | 9          | 4          | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | NE         |
    | 1          | 10         | 31         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | N          |
    +------------+------------+------------+------------+------------------+-------------------+------------+----------------+
  3. 寫入資料至非分區外表,並查看資料是否已成功寫入。

    INSERT INTO mc_oss_csv_external1 VALUES(1,12,76,1,46.81006,-92.08174,'9/14/2014 0:10','SW');
    SELECT * FROM mc_oss_csv_external1 WHERE recordId=12;

    返回結果如下:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 1          | 12         | 76         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:10 | SW         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+

    查看OSS路徑Demo1/下已產生新檔案。image

樣本二:分區表

  1. 樣本資料中的Demo2/目錄建立映射關係。建立OSS外部表格並引入分區資料的命令樣本如下。

    CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external2
    (
      vehicleId INT,
      recordId INT,
      patientId INT,
      calls INT,
      locationLatitute DOUBLE,
      locationLongtitue DOUBLE,
      recordTime STRING
    )
    PARTITIONED BY (
      direction STRING
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole'
    ) 
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo2/';
    
    -- 可以執行DESC EXTENDED mc_oss_csv_external2;命令查看建立好的外部表格結構資訊。

    樣本中使用的角色為aliyunodpsdefaultrole,如果使用其他角色,需要將aliyunodpsdefaultrole替換為目標角色名稱,並為目標角色授予訪問OSS的許可權。

  2. 引入分區資料。當建立的OSS外部表格為分區表時,需要額外執行引入分區資料的操作,更多操作請參見補全OSS外部表格分區資料文法

    MSCK REPAIR TABLE mc_oss_csv_external2 ADD PARTITIONS;
    
    -- 等效於如下語句。
    ALTER TABLE mc_oss_csv_external2 ADD PARTITION (direction = 'N') 
      PARTITION (direction = 'NE') PARTITION (direction = 'S') 
      PARTITION (direction = 'SW') PARTITION (direction = 'W');
  3. 查詢分區外表。

    SELECT * FROM mc_oss_csv_external2 WHERE direction='NE';

    返回結果如下:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 1          | 2          | 13         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         |
    | 1          | 3          | 48         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         |
    | 1          | 9          | 4          | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | NE         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
  4. 寫入資料至分區外表,並查看是否已成功寫入。

    INSERT INTO mc_oss_csv_external2 PARTITION(direction='NE') VALUES(1,12,76,1,46.81006,-92.08174,'9/14/2014 0:10');
    SELECT * FROM mc_oss_csv_external2 WHERE direction='NE' AND recordId=12;

    返回結果如下:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime     | direction  |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 1          | 12         | 76         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:10 | NE         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+

    查看OSS路徑Demo2/direction=NE下已產生新檔案。image

樣本三:壓縮資料

本樣本建立以GZIP壓縮的CSV格式外表,進行資料讀取和寫入操作。

  1. 建立內部表並寫入測試資料,用來進行後續的寫入測試。

    CREATE TABLE vehicle_test(
      vehicleid INT, 
      recordid INT, 
      patientid INT, 
      calls INT, 
      locationlatitute DOUBLE, 
      locationlongtitue DOUBLE, 
      recordtime STRING, 
      direction STRING
    );
    
    INSERT INTO vehicle_test VALUES (1,1,51,1,46.81006,-92.08174,'9/14/2014 0:00','S');
  2. 建立以GZIP壓縮的CSV格式外表,與樣本資料中的Demo3/(壓縮資料)目錄建立映射關係。建立OSS外部表格命令樣本如下。

    CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external3
    (
      vehicleId INT,
      recordId INT,
      patientId INT,
      calls INT,
      locationLatitute DOUBLE,
      locationLongtitue DOUBLE,
      recordTime STRING,
      direction STRING
    )
    PARTITIONED BY (dt STRING)
    STORED BY 'com.aliyun.odps.CsvStorageHandler' 
    WITH serdeproperties (
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole',
      'odps.text.option.gzip.input.enabled'='true',
      'odps.text.option.gzip.output.enabled'='true' 
    ) 
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo3/';
    
    -- 引入分區資料
    MSCK REPAIR TABLE mc_oss_csv_external3 ADD PARTITIONS;
    
    -- 可以執行DESC EXTENDED mc_oss_csv_external3;命令查看建立好的外部表格結構資訊。

    樣本中使用的角色為aliyunodpsdefaultrole,如果使用其他角色,需要將aliyunodpsdefaultrole替換為目標角色名稱,並為目標角色授予訪問OSS的許可權。

  3. 使用MaxCompute用戶端,從OSS中讀取資料。命令樣本如下:

    說明

    如果OSS壓縮資料為開來源資料格式,需要在SQL語句前添加set odps.sql.hive.compatible=true;命令,與SQL語句一起提交執行。

    --開啟全表掃描,僅此Session有效。
    SET odps.sql.allow.fullscan=true;
    SELECT recordId, patientId, direction FROM mc_oss_csv_external3 WHERE patientId > 25;

    返回結果如下:

    +------------+------------+------------+
    | recordid   | patientid  | direction  |
    +------------+------------+------------+
    | 1          | 51         | S          |
    | 3          | 48         | NE         |
    | 4          | 30         | W          |
    | 5          | 47         | S          |
    | 7          | 53         | N          |
    | 8          | 63         | SW         |
    | 10         | 31         | N          |
    +------------+------------+------------+
  4. 讀取內部表的資料寫入至OSS外表。

    通過MaxCompute用戶端對外部表格執行INSERT OVERWRITEINSERT INTO命令,將資料寫入OSS。

    INSERT INTO TABLE mc_oss_csv_external3 PARTITION (dt='20250418') SELECT * FROM vehicle_test;

    執行成功後,可在OSS目錄下查看匯出的檔案。

建立OSS外部表格並指定對應OSS檔案的第一行為表頭

樣本資料oss-mc-testBucket下建立Demo11目錄,並執行如下語句:

--建立外部表格
CREATE EXTERNAL TABLE mf_oss_wtt
(
  id BIGINT,
  name STRING,
  tran_amt DOUBLE
)
STORED BY 'com.aliyun.odps.CsvStorageHandler'
WITH serdeproperties (
  'odps.text.option.header.lines.count' = '1',
  'odps.sql.text.option.flush.header' = 'true'
)
LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo11/';

--插入資料
INSERT OVERWRITE TABLE mf_oss_wtt VALUES (1, 'val1', 1.1),(2, 'value2', 1.3);

--查詢資料
--在建表的時候可以把所有欄位建成string,否則表頭讀取時會報錯。
--或者在建表的時候需要加跳過表頭的參數:'odps.text.option.header.lines.count' = '1'
SELECT * FROM mf_oss_wtt;

樣本中使用的角色為aliyunodpsdefaultrole,如果使用其他角色,需要將aliyunodpsdefaultrole替換為目標角色名稱,並為目標角色授予訪問OSS的許可權。

返回結果如下:

+----------+--------+------------+
| id       | name   | tran_amt   |
+----------+--------+------------+
| 1        | val1   | 1.1        |
| 2        | value2 | 1.3        |
+----------+--------+------------+

建立OSS外部表格且外部表格列數與OSS資料列數不一致

  1. 樣本資料oss-mc-testBucket下建立demo目錄,並上傳test.csv檔案。test.csv檔案內容如下。

    1,kyle1,this is desc1
    2,kyle2,this is desc2,this is two
    3,kyle3,this is desc3,this is three, I have 4 columns
  2. 建立外部表格。

    1. 指定對於列數不一致的行的處理方式為TRUNCATE

      -- 刪除表
      DROP TABLE test_mismatch;
      -- 建立外部表格
      CREATE EXTERNAL TABLE IF NOT EXISTS test_mismatch
      (
        id string,
        name string,
        dect string,
        col4 string
      )
      STORED BY 'com.aliyun.odps.CsvStorageHandler'
      WITH serdeproperties ('odps.sql.text.schema.mismatch.mode' = 'truncate')
      LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/';
    2. 指定對於列數不一致的行的處理方式為IGNORE

      -- 刪除表
      DROP TABLE test_mismatch01;
      -- 建立外部表格
      CREATE EXTERNAL TABLE IF NOT EXISTS test_mismatch01
      (
        id STRING,
        name STRING,
        dect STRING,
        col4 STRING
      )
      STORED BY 'com.aliyun.odps.CsvStorageHandler'
      WITH serdeproperties ('odps.sql.text.schema.mismatch.mode' = 'ignore')
      LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/';
    3. 查詢表資料。

      • 查詢test_mismatch表。

        SELECT * FROM test_mismatch;
        
        --返回結果
        +----+-------+---------------+---------------+
        | id | name  | dect          | col4          |
        +----+-------+---------------+---------------+
        | 1  | kyle1 | this is desc1 | NULL          |
        | 2  | kyle2 | this is desc2 | this is two   |
        | 3  | kyle3 | this is desc3 | this is three |
        +----+-------+---------------+---------------+
      • 查詢test_mismatch01表。

        SELECT * FROM test_mismatch01;
        
        --返回結果
        +----+-------+----------------+-------------+
        | id | name  | dect           | col4        |
        +----+-------+----------------+-------------+
        | 2  | kyle2 | this is desc2  | this is two  
        +----+-------+----------------+-------------+

通過內建開源解析器建立OSS外部表格

通過內建開源解析器建立OSS外部表格讀取以逗號為分隔字元的檔案,並忽略首行和尾行的資料。

  1. 樣本資料oss-mc-testBucket下建立demo-test目錄,並上傳測試檔案test.csv

    測試檔案包含的資料資訊如下。

    1,1,51,1,46.81006,-92.08174,9/14/2014 0:00,S
    1,2,13,1,46.81006,-92.08174,9/14/2014 0:00,NE
    1,3,48,1,46.81006,-92.08174,9/14/2014 0:00,NE
    1,4,30,1,46.81006,-92.08174,9/14/2014 0:00,W
    1,5,47,1,46.81006,-92.08174,9/14/2014 0:00,S
    1,6,9,1,46.81006,-92.08174,9/15/2014 0:00,S
    1,7,53,1,46.81006,-92.08174,9/15/2014 0:00,N
    1,8,63,1,46.81006,-92.08174,9/15/2014 0:00,SW
    1,9,4,1,46.81006,-92.08174,9/15/2014 0:00,NE
    1,10,31,1,46.81006,-92.08174,9/15/2014 0:00,N
  2. 建立外部表格,並指定分隔字元為逗號,設定忽略首行和尾行參數。

    CREATE EXTERNAL TABLE ext_csv_test08
    (
      vehicleId INT,
      recordId INT,
      patientId INT,
      calls INT,
      locationLatitute DOUBLE,
      locationLongtitue DOUBLE,
      recordTime STRING,
      direction STRING
    )
    ROW FORMAT serde 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
    WITH serdeproperties (
    "separatorChar" = ","
    )
    stored AS textfile
    location 'oss://oss-cn-hangzhou-internal.aliyuncs.com/***/'
    -- 設定忽略首行和尾行參數。
    TBLPROPERTIES (
    "skip.header.line.COUNT"="1",
    "skip.footer.line.COUNT"="1"
    )
    ;
  3. 讀取外部表格。

    SELECT * FROM ext_csv_test08;
    
    -- 返回結果,唯讀了8條,忽略了首行和尾行。
    +------------+------------+------------+------------+------------------+-------------------+------------+------------+
    | vehicleid  | recordid   | patientid  | calls      | locationlatitute | locationlongtitue | recordtime | direction  | 
    +------------+------------+------------+------------+------------------+-------------------+------------+------------+
    | 1          | 1          | 51         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | S          | 
    | 1          | 2          | 13         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         | 
    | 1          | 3          | 48         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | NE         | 
    | 1          | 4          | 30         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | W          | 
    | 1          | 5          | 47         | 1          | 46.81006         | -92.08174         | 9/14/2014 0:00 | S          | 
    | 1          | 6          | 9          | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | S          | 
    | 1          | 7          | 53         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | N          | 
    | 1          | 8          | 63         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | SW         | 
    | 1          | 9          | 4          | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | NE         | 
    | 1          | 10         | 31         | 1          | 46.81006         | -92.08174         | 9/15/2014 0:00 | N          | 
    +------------+------------+------------+------------+------------------+-------------------+------------+------------+

建立CSV格式的OSS外部表格-自訂各種時間資料類型

CSV自訂時間類型的解析與輸出格式詳情,請參見Smart Parse更靈活的類型相容能力

  1. 建立各時間資料類型的CSV外表(datetime/timestamp/timestamp_ntz)。

    CREATE EXTERNAL TABLE test_csv
    (
      col_date DATE,
      col_datetime DATETIME,
      col_timestamp TIMESTAMP,
      col_timestamp_ntz TIMESTAMP_NTZ
    )
    STORED BY 'com.aliyun.odps.CsvStorageHandler'
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/'
    TBLPROPERTIES (
      'odps.text.option.date.io.format' = 'MM/dd/yyyy',
      'odps.text.option.datetime.io.format' = 'yyyy-MM-dd-HH-mm-ss x',
      'odps.text.option.timestamp.io.format' = 'yyyy-MM-dd HH-mm-ss VV',
      'odps.text.option.timestamp_ntz.io.format' = 'yyyy-MM-dd HH:mm:ss.SS'
    );
    
    INSERT OVERWRITE test_csv 
      VALUES(DATE'2025-02-21', DATETIME'2025-02-21 08:30:00', TIMESTAMP'2025-02-21 12:30:00', TIMESTAMP_NTZ'2025-02-21 16:30:00.123456789');
  2. 插入資料後,CSV檔案的內容為:

    02/21/2025,2025-02-21-08-30-00 +08,2025-02-21 12-30-00 Asia/Shanghai,2025-02-21 16:30:00.12
  3. 再次讀資料,可以看到結果。

    SELECT * FROM test_csv;

    返回結果如下:

    +------------+---------------------+---------------------+------------------------+
    | col_date   | col_datetime        | col_timestamp       | col_timestamp_ntz      |
    +------------+---------------------+---------------------+------------------------+
    | 2025-02-21 | 2025-02-21 08:30:00 | 2025-02-21 12:30:00 | 2025-02-21 16:30:00.12 |
    +------------+---------------------+---------------------+------------------------+

常見問題

讀取CSV/TSV資料時會報錯“列數不匹配”

  • 問題現象

    若CSV/TSV檔案中的列數與外表DDL中的列數量的不一致,讀取CSV/TSV資料時會報錯“列數不匹配”,例如FAILED: ODPS-0123131:User defined function exception - Traceback:java.lang.RuntimeException: SCHEMA MISMATCH:xxx

  • 解決方案

    通過在Session層級設定odps.sql.text.schema.mismatch.mode參數,可以控制輸出結果:

    • SET odps.sql.text.schema.mismatch.mode=error:表示列數不一致時,系統直接報錯。

    • SET odps.sql.text.schema.mismatch.mode=truncate:表示列數不一致時,超過外表DDL中的列數部分將被丟棄;少於外表DDL中的列數部分,列值將被補充為NULL。