您可以使用解析器支持的选项,借助多个解析器之一加载 Flex 表。
1 - 使用 Flex 解析器加载列式表
您可以使用任何 Flex 解析器将数据加载到列式表中。使用 Flex 表解析器加载列式表使您能够在一个表中混合数据加载。例如,您可以将 JSON 数据加载到一个会话中,而将分隔数据加载到另一个会话中。
注意
对于 Avro 数据,您可以只将数据加载到列式表,而不加载架构。对于 Flex 表,则必须将 Avro 架构信息嵌入在数据中。下面的基本示例说明了您可以如何将 Flex 解析器用于列式表。
-
创建一个列式表
super
,其具有两列,分别是age
和name
:=> CREATE TABLE super(age INT, name VARCHAR); CREATE TABLE
-
使用
fjsonparser()
输入来自 STDIN 的 JSON 值。=> COPY super FROM stdin PARSER fjsonparser(); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> {"age": 5, "name": "Tim"} >> {"age": 3} >> {"name": "Fred"} >> {"name": "Bob", "age": 10} >> \.
-
查询该表以查看您输入的值:
=> SELECT * FROM super; age | name -----+------ | Fred 10 | Bob 5 | Tim 3 | (4 rows)
-
使用
fdelimitedparser()
输入来自 STDIN 的一些分隔值:=> COPY super FROM stdin PARSER fdelimitedparser(); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> name |age >> Tim|50 >> |30 >> Fred| >> Bob|100 >> \.
-
查询 Flex 表。JSON 和分隔数据均保存在同一个列式表
super
中。=> SELECT * FROM super; age | name -----+------ 50 | Tim 30 | 3 | 5 | Tim 100 | Bob | Fred 10 | Bob | Fred (8 rows)
使用 reject_on_materialized_type_error
参数避免加载类型不匹配的数据。如果 reject_on_materialized_type_error
设置为 false
,Flex 解析器将接受类型不匹配的数据。请考虑以下示例:
假定待加载的 CSV 文件具有以下示例内容:
$ cat json.dat
{"created_by":"system","site_source":"flipkart_india_kol","updated_by":"system1","invoice_id":"INVDPKOL100",
"vendor_id":"VEN15731","total_quantity":12,"created_at":"2012-01-09 23:15:52.0"}
{"created_by":"system","site_source":"flipkart_india_kol","updated_by":"system2","invoice_id":"INVDPKOL101",
"vendor_id":"VEN15732","total_quantity":14,"created_at":"hello"}
-
创建列式表。
=> CREATE TABLE hdfs_test ( site_source VARCHAR(200), total_quantity int , vendor_id varchar(200), invoice_id varchar(200), updated_by varchar(200), created_by varchar(200), created_at timestamp );
-
加载 JSON 数据。
=>COPY hdfs_test FROM '/home/dbadmin/json.dat' PARSER fjsonparser() ABORT ON ERROR; Rows Loaded ------------- 2 (1 row)
-
查看内容。
=> SELECT * FROM hdfs_test; site_source | total_quantity | vendor_id | invoice_id | updated_by | created_by | created_at --------------------+----------------+-----------+-------------+------------+------------+--------------------- flipkart_india_kol | 12 | VEN15731 | INVDPKOL100 | system1 | system | 2012-01-09 23:15:52 flipkart_india_kol | 14 | VEN15732 | INVDPKOL101 | system2 | system | (2 rows)
-
如果
reject_on_materialized_type_error
参数设置为true
,您将在加载示例 JSON 数据时收到错误消息。=> COPY hdfs_test FROM '/home/dbadmin/data/flex/json.dat' PARSER fjsonparser(reject_on_materialized_type_error=true) ABORT ON ERROR; ERROR 2035: COPY: Input record 2 has been rejected (Rejected by user-defined parser)
2 - 加载 CSV 数据
使用 fcsvparser
加载 CSV 格式(逗号分隔值)的数据。由于不存在正式的 CSV 标准,Vertica 支持 RFC 4180 标准为 fcsvparser
的默认行为。其他解析器参数则将 CSV 选项的各种组合简化成列式表或 Flex 表。使用 fcsvparser
解析以下 CSV 数据格式:
-
**RFC 4180:**Vertica Flex 表的 RFC4180 CSV 格式解析器。此格式的参数为固定值,无法更改。
-
传统: 传统 CSV 解析器允许您指定参数值,如分隔符或记录终止符。有关参数的详细列表,请参阅 FCSVPARSER。
使用默认解析器设置
这些固定的参数设置适用于 RCF4180 格式。
您可以对 enclosed_by
和 escape
使用相同的值。其他值必须唯一。
使用 type
参数指示文件符合 RFC 4180 格式还是传统格式。您可以将 type
指定为 RCF4180
。但您必须首先验证数据是否与前面 RFC4180 格式参数的固定值兼容。type
参数的默认值为 RFC4180.
加载 CSV 数据 (RFC4180)
请按照以下步骤,使用 fcsvparser
加载 RFC4180 CSV 数据格式的数据。
要执行此任务,假定待加载的 CSV 文件具有以下示例内容:
$ more /home/dbadmin/flex/flexData1.csv
sno,name,age,gender
1,John,14,male
2,Mary,23,female
3,Mark,35,male
-
创建 Flex 表:
=> CREATE FLEX TABLE csv_basic(); CREATE TABLE
-
使用
fcsvparser
从 CSV 文件加载数据:=> COPY csv_basic FROM '/home/dbadmin/flex/flexData1.csv' PARSER fcsvparser(); Rows Loaded ------------- 3 (1 row)
-
查看加载到 Flex 表中的数据:
=> SELECT maptostring(__raw__) FROM csv_basic; maptostring ---------------------------------------------------------------------------------- { "age" : "14", "gender" : "male", "name" : "John", "sno" : "1" } { "age" : "23", "gender" : "female", "name" : "Mary", "sno" : "2" } { "age" : "35", "gender" : "male", "name" : "Mark", "sno" : "3" } (3 rows)
加载 CSV 数据(传统)
请按照以下步骤,使用 fcsvparser
加载传统 CSV 数据格式的数据。
在此示例中,CSV 文件将 $
用作 delimiter
,将 #
用作 record_terminator
。待加载的示例 CSV 文件具有以下内容:
$ more /home/dbadmin/flex/flexData1.csv
sno$name$age$gender#
1$John$14$male#
2$Mary$23$female#
3$Mark$35$male#
-
创建 Flex 表:
=> CREATE FLEX TABLE csv_basic(); CREATE TABLE
-
使用带有参数
type='traditional'
、delimiter='$'
和record_terminator='#'
的fscvparser
加载 Flex 表中的数据:=> COPY csv_basic FROM '/home/dbadmin/flex/flexData2.csv' PARSER fcsvparser(type='traditional', delimiter='$', record_terminator='#'); Rows Loaded ------------- 3 (1 row)
-
查看加载到 Flex 表中的数据:
=> SELECT maptostring(__raw__) FROM csv_basic; maptostring ---------------------------------------------------------------------------------- { "age" : "14", "gender" : "male", "name" : "John", "sno" : "1" } { "age" : "23", "gender" : "female", "name" : "Mary", "sno" : "2" } { "age" : "35", "gender" : "male", "name" : "Mark", "sno" : "3" } (3 rows)
拒绝重复值
您可以通过使用 fcsvparser
的 reject_on_duplicate=true
选项拒绝重复值。加载在拒绝重复值后继续。下个示例演示了如何使用此参数,接着显示了指定的异常和拒绝的数据文件。将被拒绝的数据保存到表而不是文件中,包括数据及其异常。
=> CREATE FLEX TABLE csv_basic();
CREATE TABLE
=> COPY csv_basic FROM stdin PARSER fcsvparser(reject_on_duplicate=true)
exceptions '/home/dbadmin/load_errors/except.out' rejected data '/home/dbadmin/load_errors/reject.out';
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> A|A
>> 1|2
>> \.
=> \! cat /home/dbadmin/load_errors/reject.out
A|A
=> \! cat /home/dbadmin/load_errors/except.out
COPY: Input record 1 has been rejected (Processed a header row with duplicate keys with
reject_on_duplicate specified; rejecting.). Please see /home/dbadmin/load_errors/reject.out,
record 1 for the rejected record.
COPY: Loaded 0 rows, rejected 1 rows.
拒绝包含实体化列类型错误的数据
fcsvparser
解析器具有一个布尔参数 reject_on_materialized_type_error
。将此参数设置为 true
将导致行被拒绝,前提是输入数据中同时存在以下情况:
-
包括与现有实体化列匹配的键
-
具有无法强迫采用实体化列数据类型的键值
以下示例演示了如何设置该参数。
-
创建一个表
reject_true_false
,带有两个实际列:=> CREATE FLEX TABLE reject_true_false(one int, two int); CREATE TABLE
-
使用
fcsvparser
在reject_on_materialized_type_error=false
的情况下将 CSV 数据加载至表(从 STDIN 中)中。虽然false
是默认值,但您可以显式指定它,如下所示。此外,设置参数header=true
以指定输入值对应的列:=> COPY reject_true_false FROM stdin PARSER fcsvparser(reject_on_materialized_type_error=false,header=true); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> one,two >> 1,2 >> "3","four" >> "five",6 >> 7,8 >> \.
-
调用
maptostring
在加载数据之后显示表值:=> SELECT maptostring(__raw__), one, two FROM reject_true_false; maptostring | one | two ----------------------------------------+-----+----- { "one" : "1", "two" : "2" } | 1 | 2 { "one" : "3", "two" : "four" } | 3 | { "one" : "five", "two" : "6" } | | 6 { "one" : "7", "two" : "8" } | 7 | 8 (4 rows)
-
截断该表以清空表中存储的数据:
=> TRUNCATE TABLE reject_true_false; TRUNCATE TABLE
-
重新加载相同的数据,但这次请设置
reject_on_materialized_type_error=true
:=> COPY reject_true_false FROM stdin PARSER fcsvparser(reject_on_materialized_type_error=true,header=true); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> one,two >> 1,2 >> "3","four" >> "five",6 >> 7,8 >> \.
-
调用
maptostring
显示表内容。当前仅加载两行,而之前的结果中有四行。含有数据类型不正确的输入值的行已被拒绝:=> SELECT maptostring(__raw__), one, two FROM reject_true_false; maptostring | one | two -------------------------------------+-----+----- { "one" : "1", "two" : "2" } | 1 | 2 { "one" : "7", "two" : "8" } | 7 | 8 (2 rows)
注意
如果存在类型不匹配,解析器fcsvparser
将使用 null
值;而您将 reject_on_materialized_type_error
参数设置为 false
。
拒绝或忽略空行
有效的 CSV 文件可能包含空键值对。这些行对 SQL 无效。您可以使用两个布尔 FCSVPARSER
参数拒绝或忽略空行,从而控制其行为:
reject_on_empty_key
omit_empty_keys
下面的示例演示了如何设置这些参数:
-
创建 Flex 表:
=> CREATE FLEX TABLE csv_basic(); CREATE TABLE
-
使用
fcsvparser
在reject_on_empty_key=false
的情况下将 CSV 数据加载至表(从 STDIN 中)中。虽然false
是默认值,但您可以显式指定它,如下所示。此外,设置参数header=true
以指定输入值对应的列:=> COPY csv_basic FROM stdin PARSER fcsvparser(reject_on_empty_key=false,header=true); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> ,num >> 1,2 >> \.
-
调用
maptostring
在加载数据之后显示表值:=>SELECT maptostring(__raw__) FROM csv_basic; maptostring ---------------------------------- { "" : "1", "num" : "2" } (1 row)
-
截断该表以清空表中存储的数据:
=> TRUNCATE TABLE csv_basic; TRUNCATE TABLE
-
重新加载相同的数据,但这次请设置
reject_on_empty_key=true
:=> COPY csv_basic FROM stdin PARSER fcsvparser(reject_on_empty_key=true,header=true); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> ,num >> 1,2 >> \.
-
调用
maptostring
显示表内容。未加载任何行,因为其中一个键为空:=>SELECT maptostring(__raw__) FROM csv_basic; maptostring ------------- (0 rows)
-
截断该表以清空表中存储的数据:
=> TRUNCATE TABLE csv_basic; TRUNCATE TABLE
-
重新加载相同的数据,但这次请设置
omit_empty_keys=true
:=> COPY csv_basic FROM stdin PARSER fcsvparser(omit_empty_keys=true,header=true); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> ,num >> 1,2 >> \.
-
调用
maptostring
显示表内容。现已加载一行,带空键的行已被忽略:=> SELECT maptostring(__raw__) FROM csv_basic; maptostring --------------------- { "num" : "2" } (1 row)
注意
如果不存在标题名称,则fcsvparser
使用默认标题
ucoln
,其中 n 是列偏移量。如果表的标题名称与键名相匹配,则解析器将为列加载匹配键的关联值。
使用 NULL 参数
使用带有 fcsvparser
的 COPY NULL
元数据参数,将 NULL 值加载到 Flex 表中。
下面的示例使用此参数:
-
创建 Flex 表:
=> CREATE FLEX TABLE fcsv(c1 int); CREATE TABLE
-
使用 STDIN 和 NULL 参数将 CSV 数据加载到 Flex 表中:
=> COPY fcsv FROM STDIN PARSER fcsvparser() NULL 'NULL' ; Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> a,b,c1 >> 10,20,NULL >> 20,30,50 >> 20,30,40 >> \.
-
使用
compute_flextable_keys_and_build_view
函数计算键并构建 Flex 视图:=> SELECT compute_flextable_keys_and_build_view('fcsv'); compute_flextable_keys_and_build_view -------------------------------------------------------------------------------- Please see public.fcsv_keys for updated keys The view public.fcsv_view is ready for querying (1 row)
-
查看 Flex 视图并替换 NULL 值:
=> SELECT * FROM public.fcsv_view; a | b | c1 ----+----+---- 20 | 30 | 50 10 | 20 | 20 | 30 | 40 (3 rows)
=> SELECT a,b, ISNULL(c1,-1) from public.fcsv_view; a | b | ISNULL ----+----+-------- 20 | 30 | 50 10 | 20 | -1 20 | 30 | 40 (3 rows)
处理列标题
fcsvparser 允许您使用 HEADER_NAMES=
参数指定您自己的列标题。此参数完全替换 CSV 源标题行中的列名。
例如,要将这六个列标题用于您正在加载的 CSV 文件,请使用 fcsvparser 参数,如下所示:
HEADER_NAMES='FIRST, LAST, SOCIAL_SECURITY, TOWN, STATE, COUNTRY'
如果提供比现有数据列更少的标题名称,则 fcsvparser 在您提供的名称之后使用默认名称。默认标题名称由
ucoln
组成,其中 n 是列偏移量,第一列从 0
开始。例如,如果您为 6 列表提供四个标题名称,fcsvparser 会在您提供的第四个标题名称之后提供默认名称 ucol4
和 ucol5
。
如果您提供的标题多于现有表列,则任何其他标题都将保持未使用状态。
3 - 加载分隔的数据
您可以使用两种分隔解析器(fdelimitedparser
和 fdelimitedpairparser
)之一加载 Flex 表。
-
数据通过各行的数据指定列名称时,使用
fdelimitedpairparser
。 -
数据不指定列名称或具有与列名称对应的标题行时,使用
fdelimitedparser
。
本节将介绍如何使用 fdelimitedpairparser
和 fdelimitedparser 支持的一些选项。
拒绝重复值
您可以通过使用 fdelimitedparser
的 reject_on_duplicate=true
选项拒绝重复值。加载在拒绝重复值后继续。下个示例演示了如何使用此参数,接着显示了指定的异常和拒绝的数据文件。将被拒绝的数据保存到表而不是文件中,包括数据及其异常。
=> CREATE FLEX TABLE delim_dupes();
CREATE TABLE
=> COPY delim_dupes FROM stdin PARSER fdelimitedparser(reject_on_duplicate=true)
exceptions '/home/dbadmin/load_errors/except.out' rejected data '/home/dbadmin/load_errors/reject.out';
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> A|A
>> 1|2
>> \.
=> \! cat /home/dbadmin/load_errors/reject.out
A|A
=> \! cat /home/dbadmin/load_errors/except.out
COPY: Input record 1 has been rejected (Processed a header row with duplicate keys with
reject_on_duplicate specified; rejecting.). Please see /home/dbadmin/load_errors/reject.out,
record 1 for the rejected record.
COPY: Loaded 0 rows, rejected 1 rows.
拒绝实体化列类型错误
fjsonparser
解析器和 fdelimitedparser
解析器都具有一个布尔参数 reject_on_materialized_type_error
。将此参数设置为 true
将导致行被拒绝,前提是输入数据中同时存在以下情况:
-
包括与现有实体化列匹配的键
-
具有无法强迫采用实体化列的数据类型的值
假定 Flex 表具有实体化的列 OwnerPercent
,声明为 FLOAT
。试图加载带 OwnerPercent
键(值为 VARCHAR
)的行将导致 fdelimitedparser
拒绝该数据行。
以下示例演示了如何设置该参数。
-
创建一个表
reject_true_false
,带有两个实际列:=> CREATE FLEX TABLE reject_true_false(one VARCHAR, two INT); CREATE TABLE
-
使用
fjsonparser
在reject_on_materialized_type_error=false
的情况下将 JSON 数据(从STDIN
)加载至表中。尽管false
是默认值,以下示例将显示指定该值以进行演示:=> COPY reject_true_false FROM stdin PARSER fjsonparser(reject_on_materialized_type_error=false); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> {"one": 1, "two": 2} >> {"one": "one", "two": "two"} >> {"one": "one", "two": 2} >> \.
-
调用
maptostring
在加载数据之后显示表值:=> SELECT maptostring(__raw__), one, two FROM reject_true_false; maptostring | one | two ----------------------------------+-----+----- { "one" : "one", "two" : "2" } | one | 2 { "one" : "1", "two" : "2" } | 1 | 2 { "one" : "one", "two" : "two" } | one | (3 rows)
-
截断该表:
=> TRUNCATE TABLE reject_true_false;
-
重新加载相同的数据,但这次请设置
reject_on_materialized_type_error=true
:=> COPY reject_true_false FROM stdin PARSER fjsonparser(reject_on_materialized_type_error=true); Enter data to be copied followed by a newline. End with a backslash and a period on a line by itself. >> {"one": 1, "two": 2} >> {"one": "one", "two": "two"} >> {"one": "one", "two": 2} >> \.
-
调用
maptostring
显示表内容。仅加载两行,而之前的结果中有三行:=> SELECT maptostring(__raw__), one, two FROM reject_true_false; maptostring | one | two ---------------------------------------+-----+----- { "one" : "1", "two" : "2" } | 1 | 2 { "one" : "one", "two" : "2" } | one | 2 (2 rows)