在加载期间转换数据
为增强数据库的一致性并减少使用脚本转换源数据的需要,您可以在加载过程中使用表达式转换数据。通过在加载时转换数据,您可以计算要插入到目标列中的值,这些值可以来自其他列,也可以来自您作为 FILLER 列加载的数据中的值(请参阅根据数据文件列派生表列)。您可以将要加载的数据转换为标量类型和原生数组的列,但不能转换为其他复杂类型。
例如,您的文本数据可能与 UTF-8(Vertica 期望采用的编码)不兼容。您可以在加载过程中使用 MAKEUTF8 函数移除或替换非 UTF-8 字符,如加载时转换数据中所示。或者,您可能希望从单个输入日期中提取与日、月和年对应的字段。
在加载期间转换数据时,您可以正常将数据加载到列中,然后在表达式中使用该列填充另一列。COPY 语句必须始终至少包含一个已解析的列,该列可以是 FILLER 列。您可以在 COPY 语句中穿插已解析的列和已计算的列。
以下示例将从单个输入日期列中提取与日、月和年对应的列:
=> CREATE TABLE purchases
(id INT, year VARCHAR(10), month VARCHAR(10), day VARCHAR(10), ts TIMESTAMP);
=> COPY purchases (id, year AS TO_CHAR(ts,'YYYY'),
month AS TO_CHAR(ts,'MM'), day AS TO_CHAR(ts, 'DD'),
ts FORMAT 'YYYY-MM-DD') FROM STDIN;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> 1943|2021-03-29
>> 1256|2021-03-30
>> 1512|2021-03-31
>> \.
=> SELECT * FROM purchases;
id | year | month | day | ts
------+------+-------+-----+---------------------
1256 | 2021 | 03 | 30 | 2021-03-30 00:00:00
1512 | 2021 | 03 | 31 | 2021-03-31 00:00:00
1943 | 2021 | 03 | 29 | 2021-03-29 00:00:00
(3 rows)
输入数据有两列:id
和 ts
(时间戳)。COPY 语句会使用 FORMAT 选项来指定时间戳列的格式。TO_CHAR 函数会使用该格式信息来提取 year
、month
和 day
列。
在 COPY 语句中使用表达式
COPY 语句中的表达式可以简单到只有一列,也可以更加复杂,例如使用多列的选择语句。一个表达式可以指定多个列,多个表达式可以引用同一个已解析的列。您可以对所有受支持数据类型的列使用表达式。
COPY 表达式可以使用许多 SQL 函数、运算符、常量、NULL 和注释,包括以下函数:
要求和限制:
-
对于已计算的列,您必须在 COPY 语句表达式中列出所有已解析的列。请勿在已计算列的源数据中指定 FORMAT 或 RAW。
-
表达式的返回数据类型必须可以转换到目标列的返回数据类型。已解析列参数也会进行转换,以与表达式匹配。
处理表达式错误
COPY 语句中的表达式错误是 SQL 错误。因此,它们的处理方式与解析错误不同。当发生解析错误时,COPY 会拒绝该行并将其添加到拒绝数据文件或表中。COPY 还会将拒绝行的原因添加到异常文件或拒绝数据表中。例如,COPY 解析不会隐式转换数据类型。如果正在加载的数据与列类型之间出现类型不匹配(例如,尝试将文本值加载到 FLOAT 列中),COPY 将拒绝该行并继续处理数据。
如果 COPY 语句中的表达式出现错误,则默认情况下整个加载都会失败。例如,如果 COPY 语句使用函数表达式,并且该表达式中存在语法错误,则整个加载将回退。所有 SQL 错误(包括由回退 COPY 引起的错误)都存储在 Vertica 日志文件中。但是,与解析拒绝和异常消息不同,SQL 表达式错误很简短,可能需要进一步研究。
您可以让 COPY 处理转换表达式中的错误,例如解析错误。将拒绝的行添加到同一个文件或表中,并将异常添加到同一个异常文件或表中。要启用此行为,请将 CopyFaultTolerantExpressions 配置参数设置为 1。(请参阅常规参数。)
加载含有表达式拒绝的数据可能比加载相同数量的解析拒绝更慢。如果数据存在一些错误行,则需启用表达式拒绝,以允许加载剩余数据。如果您担心完成包含许多错误行的加载所需的时间较长,请使用 REJECTMAX 参数设置限值。如果 COPY 找到 REJECTMAX 个以上的错误行,则会中止并回退加载。
有关管理拒绝数据的详细信息,请参阅处理杂乱的数据。
根据数据文件列派生表列
加载数据时,源数据可能包含目标表中不存在的一个或多个列。或者,源和目标表拥有匹配的列,但是您想从目标表中忽略一个或多个源列。
使用 FILLER 参数能够标识源数据所在的列,COPY 可以忽略源数据或将其用于计算加载到目标表的新值。需要满足以下要求:
-
定义 FILLER 参数数据类型,以便它与源数据兼容。例如,确保在目标表中定义 VARCHAR,以便其长度可以包含所有源数据;否则,数据可能会被截断。您可以通过在 COPY 语句中多次使用 FILLER 参数来指定多个 FILLER 列。
重要
如果源字段的数据类型为 VARCHAR,请务必设置 VARCHAR 长度,以确保所有 FILLER 源字段的合并长度不超过目标列定义的长度;否则,COPY 命令可能会返回错误。 -
FILLER 列的名称不能与目标表中任何列的名称匹配。
在以下示例中,该表包含名字、姓氏和全名列,但正在加载的数据包含名字、中间名和姓氏列。COPY 语句读取所有源数据,但只加载名字和姓氏的源列。它通过连接每个源数据列(包括中间名)来构造全名数据。中间名被读取为 FILLER 列,因此可以在串联中使用,但在其他情况下会被忽略。(中间名没有表格列。)
=> CREATE TABLE names(first VARCHAR(20), last VARCHAR(20), full VARCHAR(60));
CREATE TABLE
=> COPY names(first,
middle FILLER VARCHAR(20),
last,
full AS first||' '||middle||' '||last)
FROM STDIN;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> Marc|Gregory|Smith
>> Sue|Lucia|Temp
>> Jon|Pete|Hamilton
>> \.
=> SELECT * from names;
first | last | full
-------+----------+--------------------
Jon | Hamilton | Jon Pete Hamilton
Marc | Smith | Marc Gregory Smith
Sue | Temp | Sue Lucia Temp
(3 rows)