CSV and TSV external tables

更新时间:
复制 MD 格式

Learn how to create, read, and write external tables for CSV and TSV data stored in Object Storage Service (OSS).

Usage notes

  • OSS external tables do not support the cluster property.

  • The size of a single file cannot exceed 2 GB. You must split files that are larger than 2 GB.

  • MaxCompute and OSS must be in the same region.

Supported data types

For more information about MaxCompute data types, see Data Type Version 1.0 and Data Type Version 2.0.

For more information about SmartParse, see Flexible type compatibility of Smart Parse.

Type

com.aliyun.odps.CsvStorageHandler/

TsvStorageHandler

(Built-in)

org.apache.hadoop.hive.serde2.OpenCSVSerde

(Open-source)

TINYINT

Supported

Supported

SMALLINT

Supported

Supported

INT

Supported

Supported

BIGINT

Supported

Supported

BINARY

Not supported

Not supported

FLOAT

Supported

Supported

DOUBLE

Supported

Supported

DECIMAL(precision,scale)

Supported

Supported

VARCHAR(n)

Supported

Supported

CHAR(n)

Supported

Supported

STRING

Supported

Supported

DATE

Supported

Supported

DATETIME

Supported

Supported

TIMESTAMP

Supported

Supported

TIMESTAMP_NTZ

Supported

Not supported

BOOLEAN

Supported

Supported

ARRAY

Not supported

Not supported

MAP

Not supported

Not supported

STRUCT

Not supported

Not supported

JSON

Not supported

Not supported

Supported compression formats

When you read from or write to compressed OSS files, you must include the with serdeproperties attribute in the CREATE TABLE statement. For more information, see with serdeproperties attribute parameters.

Compression format

com.aliyun.odps.CsvStorageHandler/

TsvStorageHandler

(Built-in)

org.apache.hadoop.hive.serde2.OpenCSVSerde

(Open-source)

GZIP

Supported

Supported

SNAPPY

Not supported

Supported

LZO

Not supported

Supported

ZSTD

Supported

Supported

Supported schema evolution

Operation

Supported

Description

Add column

Supported

  • Adding columns with default values is not supported.

  • Adding columns of complex or nested data types is not supported.

Drop column

Supported

This operation is not recommended because it can cause a mismatch between the schema and the data.

Change column order

Supported

This operation is not recommended because it can cause a mismatch between the schema and the data.

Change column data type

Supported

For a list of supported data type conversions, see Change Column Data Type.

Rename column

Supported

Modify column comment

Supported

The comment must be a valid string with a maximum length of 1,024 bytes. Otherwise, an error occurs.

Change column nullability

Not supported

This operation is not supported. Columns are nullable by default.

Parameter configuration

The schema of a CSV or TSV external table maps to file columns by position. If the number of columns in an OSS file does not match the number of columns in the external table's schema, you can use the odps.sql.text.schema.mismatch.mode parameter to specify how to handle mismatched rows.

  • If odps.sql.text.schema.mismatch.mode is set to truncate, column modifications have the following effects:

    • Data that conforms to the new schema can be read as expected.

    • Existing data that uses the old schema is read based on the new schema.

      For example, if you add a column to a table, the historical data for that column appears as NULL when you read the table.

  • If odps.sql.text.schema.mismatch.mode is set to ignore, column modifications have the following effects:

    • Data that conforms to the new schema can be read as expected.

    • Existing data that uses the old schema is read based on the new schema.

      For example, if you add a column to a table, entire rows of historical data that lack the new column are discarded when you read the table.

  • If odps.sql.text.schema.mismatch.mode is set to error, column modifications have the following effects:

    • Data that conforms to the new schema can be read as expected.

    • Existing data that uses the old schema is read based on the new schema.

      For example, if you add a column to a table, an error occurs when you try to read historical data that lacks the new column.

Create an external table

Syntax

Built-in text parser

CSV format

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 format

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>',...)];

Built-in open-source parser

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>',...)];

Common parameters

For more information about common parameters, see Basic syntax parameters.

Format-specific parameters

WITH SERDEPROPERTIES parameters

Applicable parser

Parameter

Use case

Description

Value

Default

Built-in text data parser (CsvStorageHandler/TsvStorageHandler)

odps.text.option.gzip.input.enabled

Use this property to read CSV or TSV files that are compressed in GZIP format.

CSV and TSV compression property. Set this property to True for MaxCompute to read GZIP-compressed files. Otherwise, the read operation fails.

  • True

  • False

False

odps.text.option.gzip.output.enabled

Use this property to write data to OSS in GZIP compressed format.

CSV and TSV compression property. Set this property to True to compress data when writing to OSS. Otherwise, the data is written uncompressed.

  • True

  • False

False

odps.text.option.header.lines.count

Use this property to skip the first N rows of a CSV or TSV file in OSS.

Specifies the number of header rows to skip from the beginning of the file when reading data.

Non-negative integer

0

odps.text.option.null.indicator

Use this property to define a custom string that represents a NULL value in the data.

MaxCompute parses the specified string as a NULL value.

For example, to interpret \N in the file as NULL, set this property to \\N, where the first \ is an escape character. With this setting, a,\N,b is parsed as a, NULL, b.

string

empty string

odps.text.option.ignore.empty.lines

Use this property to define how to handle empty rows in a CSV or TSV file.

If True, MaxCompute ignores empty rows in the data file. If False, it reads them.

  • True

  • False

True

odps.text.option.encoding

Use this property when a data file does not use the default UTF-8 encoding.

The encoding specified here must match the file's actual encoding. A mismatch causes read failures.

  • UTF-8

  • UTF-16

  • US-ASCII

  • GBK

UTF-8

odps.text.option.delimiter

Use this property to specify the column delimiter for CSV or TSV files.

Ensure the specified delimiter correctly separates columns in your data file to prevent data misalignment.

Single character

Comma (,)

odps.text.option.use.quote

Use this property when a field in a CSV or TSV file contains line breaks (CRLF), double quotes, or the column delimiter.

When a field in a CSV file contains a newline, a double quote (you must add another " before the " to escape it), or a comma, the entire field must be enclosed in double quotes ("") as the column delimiter. This parameter specifies whether to recognize the CSV column delimiter ".

  • True

  • False

False

odps.sql.text.option.flush.header

Use this property to write a table header as the first row to each file block in OSS.

This property applies only to CSV files.

  • True

  • False

False

odps.sql.text.schema.mismatch.mode

Use this property when a row in the data file has a different number of columns than the external table's schema.

Specifies how to handle rows with a column count that mismatches the table schema.

Note: This feature does not work if odps.text.option.use.quote is set to True.

  • error: Reports an error and stops the query.

  • truncate: If a row has more columns than the schema, MaxCompute discards the extra columns. If it has fewer columns, MaxCompute fills the missing columns with null.

  • ignore: Discards the entire mismatched row.

error

odps.text.option.zstd.input.enabled

Use this property to read CSV or TSV files that are compressed in ZSTD format.

CSV and TSV compression property. Set this property to True for MaxCompute to read ZSTD-compressed files. Otherwise, the read operation fails.

  • True

  • False

False

odps.text.option.zstd.output.enabled

Use this property to write data to OSS in ZSTD compressed format.

CSV and TSV compression property. Set this property to True to compress data in ZSTD format when writing to OSS. Otherwise, the data is written uncompressed.

  • True

  • False

False

odps.text.option.snappy.input.enabled

Add this property when you need to read CSV or TSV files compressed with SNAPPY

(SnappyRawCodec).

CSV and TSV compression property. MaxCompute can read compressed files only when this parameter is set to True. Otherwise, the read operation fails.

  • True

  • False

False

odps.text.option.snappy.output.enabled

Add this property when you need to write data to

OSS compressed with SNAPPY (SnappyRawCodec).

CSV and TSV compression property. When this parameter is set to True, MaxCompute writes data to OSS in SNAPPY compression. Otherwise, data is written without compression.

  • True

  • False

False

Built-in open-source data parser (OpenCSVSerde)

separatorChar

Use this property to specify the column delimiter for CSV data stored as a TEXTFILE.

Specifies the column delimiter.

A single character

Comma (,)

quoteChar

Use this property when fields in CSV data contain special characters such as the delimiter or line breaks.

Specifies the character used to quote fields.

A single character

None

escapeChar

Use this property to specify the escape character for CSV data stored as a TEXTFILE.

Specifies the character used to escape special characters within a field.

A single character

None

tblproperties parameters

Applicable parser

Parameter

Use case

Description

Value

Default

Built-in open-source data parser (OpenCSVSerde)

skip.header.line.count

Use this property to skip the first N rows of a CSV file stored as a TEXTFILE.

Specifies the number of header rows to skip from the beginning of the file when reading data.

Non-negative integer

None

skip.footer.line.count

Use this property to skip the last N rows of a CSV file stored as a TEXTFILE.

Specifies the number of footer rows to skip from the end of the file when reading data.

Non-negative integer

None

mcfed.mapreduce.output.fileoutputformat.compress

Use this property to write TEXTFILE data to OSS with compression.

TEXTFILE compression property. If set to True, MaxCompute compresses the data when it is written. Otherwise, the data is written uncompressed.

  • True

  • False

False

mcfed.mapreduce.output.fileoutputformat.compress.codec

Use this property to specify the compression codec when writing compressed TEXTFILE data to OSS.

When reading compressed CSV/TSV files whose filenames contain the .bz2, .deflate, .snappy, .gz, or .zstd suffix, no additional configuration is required.

TEXTFILE compression property. Sets the compression method for TEXTFILE data files.

  • com.hadoop.compression.lzo.LzoCodec

  • com.hadoop.compression.lzo.LzopCodec

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

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

  • org.apache.hadoop.io.compress.odps.ZstandardCodec

  • org.apache.hadoop.io.compress.GzipCodec

  • org.apache.hadoop.io.compress.BZip2Codec

  • org.apache.hadoop.io.compress.DeflateCodec

None

odps.text.option.bad.row.skipping

Use this property to skip dirty data in CSV files stored in OSS.

Controls whether MaxCompute skips rows that are considered dirty data or reports an error.

  • rigid: Enforces row skipping. This setting cannot be overridden at the session or project level.

  • flexible: Enables flexible row skipping. You can override this setting with session-level or project-level configurations.

None

Whitelist and blacklist

MaxCompute OSS external tables support whitelist and blacklist filtering. By setting whitelist and blacklist parameters in tblproperties, you can filter which files to read from a directory. For details, see OSS external tables.

Write data

For details about the write syntax in MaxCompute, see Write syntax.

Query and analysis

BadRowSkipping

The BadRowSkipping feature lets you skip bad rows in CSV data that would otherwise cause a query to fail. This setting controls error handling and does not affect how the underlying data format is parsed.

Parameters

  • Table-level parameter: odps.text.option.bad.row.skipping

    • rigid: Forces skipping. This setting cannot be overridden by session-level or project-level configurations.

    • flexible: Enables skipping. This setting is flexible, allowing it to be overridden by session-level or project-level configurations.

  • session/project level parameters

    • The odps.sql.unstructured.text.bad.row.skipping parameter can override a flexible table-level parameter, but not a rigid one.

      • on: Enables the feature. If the feature is not configured for the table, it is enabled by default.

      • off: Disables the feature. If the table is configured as flexible, the feature is disabled. Otherwise, the setting of the table parameter is used.

      • <null> or invalid input: The table-level configuration is used.

    • odps.sql.unstructured.text.bad.row.skipping.debug.num: Specifies the number of error results to print to stdout in Logview.

      • The maximum value is 1000.

      • If the value is <=0, this feature is disabled.

      • If the value is invalid, this feature is disabled.

  • Interaction between session-level parameters and table properties

    tbl property

    session flag

    result

    rigid

    on

    On, Forced on

    off

    <null>, an invalid value, or the parameter is not configured

    flexible

    on

    On

    off

    Off, Disabled by session

    <null>, an invalid value, or the parameter is not configured

    On

    Not configured

    on

    On, Enabled by session

    off

    Off

    <null>, an invalid value, or the parameter is not configured

Examples

  1. Prepare the data

    Upload the test data file csv_bad_row_skipping.csv, which contains bad rows, to a directory in OSS, such as oss-mc-test/badrow/.

  2. Create the CSV external tables

    The following examples show three scenarios based on different combinations of table-level and session-level parameters.

    • Table parameter: odps.text.option.bad.row.skipping = flexible | rigid | <not set>

    • Session flag: odps.sql.unstructured.text.bad.row.skipping = on | off | <not set>

    Parameter not set

    -- No table-level parameter is set. Queries will fail on bad rows unless overridden by the session-level 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://<your-bucket-name>/<your-file-path>/>';

    Flexible skipping

    -- The table is configured to skip bad rows, but this can be disabled by the session-level 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://<your-bucket-name>/<your-file-path>/>'
    tblproperties (
      'odps.text.option.bad.row.skipping' = 'flexible'   -- Enables flexible skipping, which can be disabled at the session level.
    );

    Rigid skipping

    -- The table is configured to forcibly skip bad rows. This cannot be disabled at the session level.
    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://<your-bucket-name>/<your-file-path>/>'
    tblproperties (
      'odps.text.option.bad.row.skipping' = 'rigid'  -- Forces skipping on.
    );
  3. Verify query results

    Parameter not set

    -- The following command enables skipping, but it is immediately overridden by the next command in this example.
    SET odps.sql.unstructured.text.bad.row.skipping=on;
    
    -- This command disables skipping and is the active setting for the SELECT query below, causing it to fail.
    SET odps.sql.unstructured.text.bad.row.skipping=off;
    
    -- You can use this command to print details of skipped rows when skipping is enabled. It has no effect here because the query fails.
    SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10;
    
    SELECT * FROM test_csv_bad_data_skipping_flag;

    The query fails with the following error: FAILED: ODPS-0123131:User defined function exception

    Flexible skipping

    -- The following command enables skipping, but it is immediately overridden by the next command in this example.
    SET odps.sql.unstructured.text.bad.row.skipping=on;
    
    -- This command disables skipping, overriding the table's 'flexible' setting. It is the active setting for the SELECT query below, causing it to fail.
    SET odps.sql.unstructured.text.bad.row.skipping=off;
    
    -- Print details of up to 10 bad rows at the session level. The maximum is 1,000. A value of 0 or less disables printing.
    SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10;
    
    SELECT * FROM test_csv_bad_data_skipping_flexible;

    The query fails with the following error: FAILED: ODPS-0123131:User defined function exception

    Rigid skipping

    -- This command is redundant because the 'rigid' setting already enforces skipping.
    SET odps.sql.unstructured.text.bad.row.skipping=on;
    
    -- This command attempts to disable skipping, but it is ignored because the 'rigid' table setting cannot be overridden.
    SET odps.sql.unstructured.text.bad.row.skipping=off;
    
    -- This command prints details for up to 10 bad rows that are skipped by the 'rigid' setting.
    SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10;
    
    SELECT * FROM test_csv_bad_data_skipping_rigid;

    The following result is returned:

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

Flexible type compatibility with Smart Parse

For CSV-formatted external tables in OSS, MaxCompute SQL uses data type 2.0 for read and write operations. Previously, only values in strict formats were supported. This feature provides flexible type compatibility for reading a wide range of value formats from CSV files. The specific parsing rules are detailed below.

Type

Input as string

Output as string

Description

BOOLEAN

  • "true"/"false"

  • "T"/"F"

  • "1"/"0"

  • "Yes"/"No"

  • "Y"/"N"

  • "" (An empty string is parsed as NULL.)

Note

A trim() operation will be performed on the input during parsing.

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • "true"/"false"

  • "" (NULL values are written as an empty string to the CSV file.)

Parsing fails if the input string is not one of the supported values.

TINYINT

  • "0"

  • "1"

  • "-100"

  • "1,234,567" (thousands separator notation; commas cannot be at the start or end of the string)

  • "1_234_567" (Java-style; underscores cannot be at the start or end of the string)

  • "0.3e2" (scientific notation; parsed only if the value is an integer; otherwise, an error occurs)

  • "-1e5" (scientific notation)

  • "0xff" (hexadecimal, case-insensitive)

  • "0b1001" (binary, case-insensitive)

  • "4/2" (fraction; parsed only if the value is an integer; otherwise, an error occurs)

  • "1000%" (percentage; parsed only if the value is an integer; otherwise, an error occurs)

  • "1000‰" (per-mille; parsed only if the value is an integer; otherwise, an error occurs)

  • "1,000 $" (with currency symbol)

  • "$ 1,000" (with currency symbol)

  • "3M" (K8s-style, base-1000 unit)

  • "2Gi" (K8s-style, base-1024 unit)

  • "" (An empty string is parsed as NULL.)

Note
  • During parsing, the input undergoes atrim() operation.

  • If you use thousands separator notation, such as "1,234,567", you must set the CSV delimiter to a character other than a comma. For more information, see the usage of odps.text.option.delimiter in with serdeproperties attributes.

  • Supported K8s-style base-1000 units include K, M, G, P, and T. Base-1024 units include Ki, Mi, Gi, Pi, and Ti. For more information, see resource-management.

  • Supported currency symbols include $/¥/€/£/₩/USD/CNY/EUR/GBP/JPY/KRW/IDR/RP.

  • The strings "0", "1", "-100", and "" can also be parsed correctly in naive mode.

  • "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 values are written as an empty string to the CSV file.)

8-bit integer. An error occurs if the value is outside the range [-128, 127].

SMALLINT

16-bit integer. An error occurs if the value is outside the range [-32768, 32767].

INT

32-bit integer. An error occurs if the value is outside the range [-2147483648, 2147483647].

BIGINT

64-bit integer. An error occurs if the value is outside the range [-9223372036854775807, 9223372036854775807].

Note

The value -263 (-9223372036854775808) is outside the supported range due to a limitation in the SQL engine.

FLOAT

  • "3.14"

  • "0.314e1" (scientific notation)

  • "2/5" (fraction)

  • "123.45%" (percentage)

  • "123.45‰" (per-mille)

  • "1,234,567.89" (thousands separator notation)

  • "1,234.56 $" (with currency symbol)

  • "$ 1,234.56" (with currency symbol)

  • "1.2M" (K8s-style, base-1000 unit)

  • "2Gi" (K8s-style, base-1024 unit)

  • "NaN" (case-insensitive)

  • "Inf" (case-insensitive)

  • "-Inf" (case-insensitive)

  • "Infinity" (case-insensitive)

  • "-Infinity" (case-insensitive)

  • "" (An empty string is parsed as NULL.)

Note
  • The input undergoes a trim() operation during parsing.

  • The strings "3.14", "0.314e1", "NaN", "Infinity", "-Infinity", and "" can also be parsed correctly in naive mode.

  • "3.14"

  • "3.14"

  • "0.4"

  • "1.2345"

  • "0.12345"

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • "NaN"

  • "Infinity"

  • "-Infinity"

  • "Infinity"

  • "-Infinity"

  • "" (NULL values are written as an empty string to the CSV file.)

Special values (case-insensitive) include NaN, Inf, -Inf, Infinity, and -Infinity. An error occurs if a value is out of range. If the precision exceeds the limit, the value is rounded off.

DOUBLE

  • "3.1415926"

  • "0.314e1" (scientific notation)

  • "2/5" (fraction)

  • "123.45%" (percentage)

  • "123.45‰" (per-mille)

  • "1,234,567.89" (thousands separator notation)

  • "1,234.56 $" (with currency symbol)

  • "$ 1,234.56" (with currency symbol)

  • "1.2M" (K8s-style, base-1000 unit)

  • "2Gi" (K8s-style, base-1024 unit)

  • "NaN" (case-insensitive)

  • "Inf" (case-insensitive)

  • "-Inf" (case-insensitive)

  • "Infinity" (case-insensitive)

  • "-Infinity" (case-insensitive)

  • "" (An empty string is parsed as NULL.)

Note
  • During parsing, a trim() operation is performed on the input.

  • The strings "3.1415926", "0.314e1", "NaN", "Infinity", "-Infinity", and "" can also be parsed correctly in naive mode.

  • "3.1415926"

  • "3.14"

  • "0.4"

  • "1.2345"

  • "0.12345"

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • "NaN"

  • "Infinity"

  • "-Infinity"

  • "Infinity"

  • "-Infinity"

  • "" (NULL values are written as an empty string to the CSV file.)

Special values (case-insensitive) include NaN, Inf, -Inf, Infinity, and -Infinity. An error occurs if a value is out of range. If the precision exceeds the limit, the value is rounded off.

DECIMAL

(precision, scale)

Example: DECIMAL(15,2)

  • "3.358"

  • "2/5" (fraction)

  • "123.45%" (percentage)

  • "123.45‰" (per-mille)

  • "1,234,567.89" (thousands separator notation)

  • "1,234.56 $" (with currency symbol)

  • "$ 1,234.56" (with currency symbol)

  • "1.2M" (K8s-style, base-1000 unit)

  • "2Gi" (K8s-style, base-1024 unit)

  • "" (An empty string is parsed as NULL.)

Note
  • During parsing, the trim() operation is performed on the input.

  • The strings "3.358" and "" can also be parsed correctly in naive mode.

  • "3.36" (rounded off)

  • "0.4"

  • "1.23" (rounded off)

  • "0.12" (rounded off)

  • "1234567.89"

  • "1234.56"

  • "1234.56"

  • "1200000"

  • "2147483648"

  • "" (NULL values are written as an empty string to the CSV file.)

An error occurs if the integer part contains more than precision - scale digits. If the fractional part exceeds the specified scale, the value is rounded off.

An error is reported. If the fractional part exceeds the scale, the value is rounded off and truncated.

CHAR(n)

Example: CHAR(7)

  • "abcdefg"

  • "abcdefghijklmn"

  • "abc"

  • "" (An empty string is parsed as NULL.)

  • "abcdefg"

  • "abcdefg" (The rest of the string is truncated.)

  • "abc____" (padded with four space characters, which are represented by _)

  • "" (NULL values are written as an empty string to the CSV file.)

The maximum length is 255. If an input string is shorter than n, it is padded with trailing spaces, but these spaces are ignored in comparisons. If an input string is longer than n, it is truncated.

VARCHAR(n)

Example: VARCHAR(7)

  • "abcdefg"

  • "abcdefghijklmn"

  • "abc"

  • "" (An empty string is parsed as NULL.)

  • "abcdefg"

  • "abcdefg" (The rest of the string is truncated.)

  • "abc"

  • "" (NULL values are written as an empty string to the CSV file.)

The maximum length is 65,535. If an input string is longer than n, it is truncated.

STRING

  • "abcdefg"

  • "abc"

  • "" (An empty string is parsed as NULL.)

  • "abcdefg"

  • "abc"

  • "" (NULL values are written as an empty string to the CSV file.)

The maximum length is 8 MB.

DATE

  • "yyyy-MM-dd" (for example, "2025-02-21")

  • "yyyyMMdd" (for example, "20250221")

  • "MMM d,yyyy" (for example, "Oct 1,2025")

  • "MMMM d,yyyy" (for example, "October 1,2025")

  • "" (An empty string is parsed as NULL.)

Note

You can also set the odps.text.option.date.io.format property to control the parsing format. For example, if you set the format to 'dd/MM/yyyy#yyyy--MM--dd', MaxCompute can parse strings like '21/02/2025' and '2025--02--21'.

  • "2000-01-01"

  • "2000-01-01"

  • "" (NULL values are written as an empty string to the CSV file.)

  • This type does not contain time information, so changing the time zone does not affect the output. The default output format is "yyyy-MM-dd".

  • You can set the odps.text.option.date.io.format property to define custom parsing and output formats. The first pattern you define is used for output. For pattern syntax, see DateTimeFormatter.

TIMESTAMP_NTZ

Note

OpenCsvSerde does not support this type because it is incompatible with the Hive data format.

  • The nanosecond part can have 0 to 9 digits. MaxCompute's built-in supported formats are:

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

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

    • "yyyyMMddHHmmss" (for example, "20000101000000")

    • "" (An empty string is parsed as NULL.)

  • You can also set the odps.text.option.timestamp_ntz.io.format property to control the parsing format. For example, if you set the format to 'ddMMyyyy-HHmmss', MaxCompute can parse a string like '31102024-103055'.

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

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

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

  • "" (NULL values are written as an empty string to the CSV file.)

  • This type represents a nanosecond-precision timestamp. It is not affected by the session time zone, and its output defaults to the standard UTC time zone. The default output format is "yyyy-MM-dd HH:mm:ss.SSSSSSSSS".

  • You can set the odps.text.option.timestamp_ntz.io.format property to define custom parsing and output formats. For pattern syntax, see DateTimeFormatter.

DATETIME

  • The millisecond part can have 0 to 3 digits. [x] represents the time zone offset. Assuming the system time zone is Asia/Shanghai, MaxCompute's built-in supported formats are:

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

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

    • "yyyyMMddHHmmss[x]" (for example, "20000101000000+0000")

    • "" (An empty string is parsed as NULL.)

  • You can also set the odps.text.option.datetime.io.format property to control the parsing format. For example, if you set the format to 'yyyyMMdd-HHmmss.SSS', MaxCompute can parse a string like '20241031-103055.123'.

Assuming the system time zone is 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 values are written as an empty string to the CSV file.)

  • This type represents a millisecond-precision timestamp. The output value is affected by the session time zone. The default output format is "yyyy-MM-dd HH:mm:ss.SSSx".

  • You can set the odps.sql.timezone property to change the system time zone, which controls the time zone offset of the output value.

  • You can also set the odps.text.option.datetime.io.format property to define custom parsing and output formats. For pattern syntax, see DateTimeFormatter.

TIMESTAMP

  • The nanosecond part can have 0 to 9 digits. [x] represents the time zone offset. Assuming the system time zone is Asia/Shanghai, MaxCompute's built-in supported formats are:

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

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

    • "yyyyMMddHHmmss[x]" (for example, "20000101000000+0000")

    • "" (An empty string is parsed as NULL.)

  • You can also set the odps.text.option.timestamp.io.format property to control the parsing format. For example, if you set the format to 'yyyyMMdd-HHmmss', MaxCompute can parse a string like '20240910-103055'.

(Assuming the system time zone is 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 values are written as an empty string to the CSV file.)

  • This type represents a nanosecond-precision timestamp. The output value is affected by the session time zone. The default output format is "yyyy-MM-dd HH:mm:ss.SSSSSSSSSx".

  • You can set the odps.sql.timezone property to change the system time zone, which controls the time zone offset of the output value.

  • You can also set the odps.text.option.timestamp.io.format property to define custom parsing and output formats. For pattern syntax, see DateTimeFormatter.

  • General rules

    • For any data type, an empty string in the CSV data file is parsed as NULL when read into a table.

  • Unsupported data types

    • Complex types (STRUCT, ARRAY, MAP): Not supported. Values of these types often contain characters such as the comma (,), which can conflict with common CSV delimiters and cause parsing failures.

    • BINARY and INTERVAL: Not currently supported. If you need support for these types, contact MaxCompute technical support.

  • Numeric types (INT, DOUBLE, etc.)

    • For numeric data types such as INT, SMALLINT, TINYINT, BIGINT, FLOAT, DOUBLE, and DECIMAL, MaxCompute provides extensive default parsing capabilities.

    • If you need to parse only basic numeric strings, you can set the odps.text.option.smart.parse.level property to naive in tblproperties. In naive mode, the parser supports only simple formats like "123" and "123.456". Parsing other string formats causes an error.

  • Date and time types (DATE, TIMESTAMP, etc.)

    • The java.time.format.DateTimeFormatter class processes all four date and time types: DATE, DATETIME, TIMESTAMP, and TIMESTAMP_NTZ.

    • Default formats: MaxCompute has several built-in parsing formats.

    • Custom formats:

      • You can define multiple parsing formats and one output format by setting the odps.text.option.<date|datetime|timestamp|timestamp_ntz>.io.format property in tblproperties.

      • Use the hash symbol (#) to separate multiple parsing patterns.

      • Custom formats take precedence over the built-in formats. The first custom pattern is used for output.

      • Example: If you define the custom format string for the DATE type as pattern1#pattern2#pattern3, MaxCompute can parse strings that match pattern1, pattern2, or pattern3. However, when writing data to a file, the output will always use the format specified by pattern1. For more information, see DateTimeFormatter.

  • Important note on the 'z' time zone pattern

    • Avoid using 'z' (time-zone name) in custom formats, especially for users in China, because it is ambiguous.

    • Instead, use 'x' (zone-offset) or 'VV' (time-zone ID) for the time zone pattern.

    • Example: 'CST' typically means China Standard Time (UTC+8) in China. However, when java.time.format.DateTimeFormatter parses 'CST', it interprets it as US Central Standard Time (UTC-6), which can cause unexpected input or output results.

CSV file splitting logic

The built-in CSV/TSV parser (OpenCSVSerde)

The built-in CSV/TSV parser (OpenCSVSerde) requires each line of data in a CSV file to be separated by \r\n or similar characters, and columns must not contain \r\n The parallel splitting and data integrity logic is as follows:

  • first, the file is split by split size, and some lines may be cut in the middle.

  • When subsequent workers consume splits, all splits except the first one actively skip the leading partial or full line.

  • Each worker must also actively consume the trailing partial or full line, even if it falls within the next split's range.

This parser supports parallel splitting but does not support quote escaping.

The open-source CSV parser (CsvStorageHandler / TsvStorageHandler)

The open-source CSV parser (CsvStorageHandler / TsvStorageHandler) takes quote escaping into account when reading CSV/TSV files and supports \r\n. It can handle scenarios where special characters such as nested quotes or \r\n appear inside quotes.

For example, in the data "a\ra","b\nb","cc""cc", the \r\n and double quotes can be correctly parsed and output, supporting cross-line values. However, because the actual line break positions can only be determined through data parsing, the file cannot be simply split by \r\n. As a result, parallel consumption of a single file is not supported.

If you confirm that the data columns do not contain \r\n and \r\n is used only as a line delimiter, you can enable parallel splitting by setting odps.sql.unstructured.data.single.file.split.enabled. In this case, a large file can be divided into multiple splits by split size, and the built-in Text Extractor automatically aligns to line break boundaries to ensure data integrity.

Conclusion:

  • If the data contains \r\n that cannot be treated as a line delimiter, only the built-in CSV/TSV parser can be used.

  • Conversely, if you need to split a single large file in parallel, only the open-source CSV Serde parser can be used.

Examples

Prerequisites

Create an OSS external table with the built-in text parser

Example 1: Non-partitioned table

  1. Map the external table to the Demo1/ directory from the sample data. Use the following command to create an OSS external table.

    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/';
    
    -- You can run the `desc extended mc_oss_csv_external1;` command to view the schema of the created OSS external table.

    This example uses the aliyunodpsdefaultrole RAM role. If you use a different RAM role, replace aliyunodpsdefaultrole with the name of your target RAM role and grant it the required permissions to access OSS.

  2. Query the non-partitioned external table.

    SELECT * FROM mc_oss_csv_external1;

    The command returns the following result:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 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. Write data to the non-partitioned external table and check that the data was written successfully.

    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;

    The command returns the following result:

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

    Verify that a new file appears in the Demo1/ directory in OSS.

    After the data is written, you can view the generated result file 20250606054845430gpwnhakujm16_M1_1_0_0-0_TableSink1-0-.csv (0.046 KB) in the corresponding OSS path, along with the original data file vehicle.csv (0.45 KB).

Example 2: Partitioned table

  1. Map the external table to the Demo2/ directory from the sample data. The following sample command creates a partitioned OSS external table.

    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/';
    
    -- You can run the `DESC EXTENDED mc_oss_csv_external2;` command to view the schema of the created external table.

    This example uses the aliyunodpsdefaultrole RAM role. If you use a different RAM role, replace aliyunodpsdefaultrole with the name of your target RAM role and grant it the required permissions to access OSS.

  2. Import partition data. If you create a partitioned OSS external table, you must also import the partition data. For more information, see OSS external tables.

    MSCK REPAIR TABLE mc_oss_csv_external2 ADD PARTITIONS;
    
    -- This is equivalent to the following statement.
    ALTER TABLE mc_oss_csv_external2 ADD PARTITION (direction = 'N') 
      PARTITION (direction = 'NE') PARTITION (direction = 'S') 
      PARTITION (direction = 'SW') PARTITION (direction = 'W');
  3. Query the partitioned external table.

    SELECT * FROM mc_oss_csv_external2 WHERE direction='NE';

    The command returns the following result:

    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 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. Write data to the partitioned external table and check that the data was written successfully.

    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;

    The command returns the following result:

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

    Check that a new file is generated in the Demo2/direction=NE directory in OSS.

    The automatically generated partition data file 20250606062610590gocsdsoujm16_M1_1_0_0-0_TableSink1-0-.csv can be seen in the OSS file list, indicating that data has been successfully written to the corresponding partition path in OSS.

Example 3: Compressed data

This example shows how to create a GZIP-compressed CSV external table and perform read and write operations.

  1. Create an internal table and insert test data for a subsequent write test.

    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. Create a GZIP-compressed CSV external table and map it to the Demo3/ directory (which contains compressed data) from the sample data. The following sample command creates the OSS external table.

    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/';
    
    -- Import partition data.
    MSCK REPAIR TABLE mc_oss_csv_external3 ADD PARTITIONS;
    
    -- You can run the `DESC EXTENDED mc_oss_csv_external3;` command to view the schema of the created external table.

    This example uses the aliyunodpsdefaultrole RAM role. If you use a different RAM role, replace aliyunodpsdefaultrole with the name of your target RAM role and grant it the required permissions to access OSS.

  3. Use a MaxCompute client to read data from OSS:

    Note

    If the compressed data in OSS is in an open-source data format, you must add the set odps.sql.hive.compatible=true; command before the SQL statement and submit them together for execution.

    --Enable a full table scan for the current session only.
    SET odps.sql.allow.fullscan=true;
    SELECT recordId, patientId, direction FROM mc_oss_csv_external3 WHERE patientId > 25;

    The command returns the following result:

    +------------+------------+------------+
    | 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. Read data from the internal table and write it to the OSS external table.

    You can execute the INSERT OVERWRITE or INSERT INTO command on an external table from the MaxCompute client to write data to OSS.

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

    After the command runs successfully, you can view the exported file in the OSS directory.

Create an external table with a header row

Create a Demo11 directory in the oss-mc-test bucket from the sample data, and run the following statements:

--Create the external table.
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 data.
INSERT OVERWRITE TABLE mf_oss_wtt VALUES (1, 'val1', 1.1),(2, 'value2', 1.3);

--Query data.
--When you create the table, you can define all columns as STRING. Otherwise, an error occurs when the header is read.
--Alternatively, add the 'odps.text.option.header.lines.count' = '1' parameter to the table definition to skip the header.
SELECT * FROM mf_oss_wtt;

This example uses the aliyunodpsdefaultrole RAM role. If you use a different RAM role, replace aliyunodpsdefaultrole with the name of your target RAM role and grant it the required permissions to access OSS.

The command returns the following result:

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

Create an external table with mismatched columns

  1. Create a demo directory in the oss-mc-test bucket from the sample data and upload the test.csv file. The test.csv file contains the following content:

    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. Create the external tables.

    1. Set the handling method for rows with inconsistent column counts to TRUNCATE.

      -- Drop the table.
      DROP TABLE test_mismatch;
      -- Create the external table.
      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. Specify the handling method for rows with inconsistent column counts as IGNORE.

      -- Drop the table.
      DROP TABLE test_mismatch01;
      -- Create the external table.
      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. Query the data in the tables.

      • Query the test_mismatch table.

        SELECT * FROM test_mismatch;
        
        --Returned result
        +----+-------+---------------+---------------+
        | 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 |
        +----+-------+---------------+---------------+
      • Query the test_mismatch01 table.

        SELECT * FROM test_mismatch01;
        
        --Returned result
        +----+-------+----------------+-------------+
        | id | name  | dect           | col4        |
        +----+-------+----------------+-------------+
        | 2  | kyle2 | this is desc2  | this is two  
        +----+-------+----------------+-------------+

Create an external table with the open-source parser

This example shows how to use the built-in open source parser to create an OSS external table to read a comma-separated file while ignoring the header and footer rows.

  1. Create a demo-test directory in the oss-mc-test bucket from the sample data and upload the test.csv file.

    The test file contains the following data:

    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 the external table, specify the comma as the separator, and set parameters to ignore the header and footer rows.

    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/***/'
    -- Set parameters to ignore the header and footer rows.
    TBLPROPERTIES (
    "skip.header.line.COUNT"="1",
    "skip.footer.line.COUNT"="1"
    )
    ;
  3. Read data from the external table.

    SELECT * FROM ext_csv_test08;
    
    -- The result includes 8 rows of data because the header and footer rows are ignored.
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+
    | 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          | 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         |
    +------------+------------+------------+------------+------------------+-------------------+----------------+------------+

Create a CSV external table with custom time types

For details about parsing and output formats for custom time types in CSV, see Flexible type compatibility with Smart Parse.

  1. Create a CSV external table that uses various time data types, such as DATE, DATETIME, TIMESTAMP, and 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. After the data is inserted, the content of the CSV file is as follows:

    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. Query the data again to view the result.

    SELECT * FROM test_csv;

    The command returns the following result:

    +------------+---------------------+---------------------+------------------------+
    | 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 |
    +------------+---------------------+---------------------+------------------------+

FAQ

Column count mismatch error

  • Symptom

    This error occurs when the column count in a row of a CSV or TSV file does not match the one defined in the external table DDL. MaxCompute reports an error similar to FAILED: ODPS-0123131:User defined function exception - Traceback:java.lang.RuntimeException: SCHEMA MISMATCH:xxx.

  • Resolution

    You can control how MaxCompute handles the mismatch by setting the odps.sql.text.schema.mismatch.mode parameter at the session level:

    • SET odps.sql.text.schema.mismatch.mode=error: Fails the query when a column count mismatch occurs. This is the default behavior.

    • SET odps.sql.text.schema.mismatch.mode=truncate: If a row has more columns than defined in the external table DDL, the extra columns are discarded. If a row has fewer columns, the missing columns are filled with NULL.