SQL 格式模型¶
在 Snowflake 中,SQL 格式模型(即包含格式字符串的字面量)用于指定如何将数值转换为文本字符串,反之亦然。因此,可以将这些格式模型指定为 TO_CHAR、TO_VARCHAR 和 TO_DECIMAL、TO_NUMBER、TO_NUMERIC 转换函数中的实参。
备注
Snowflake 还为日期、时间和时间戳提供了一些有限的 SQL 格式模型支持(请参阅 日期和时间函数 以及 转换函数)。在未来的版本中,将全面支持使用 SQL 格式模型来格式化日期、时间和时间戳。
本主题内容:
格式模型的组件¶
格式模型由一串格式元素和字面量组成。
格式元素¶
格式元素是数字和/或字母(通常不区分大小写)的序列,有时也包括符号。格式元素之间可以直接连接。
有些格式元素在所有格式模型中都通用,用于控制打印和匹配输入文本。其他格式元素则具有特定用途,具体取决于其用于转换的值类型。有关更多信息,请参阅本主题中的以下部分:
格式字面量¶
格式字面量是可以由以下组合组成的序列:
由双引号分隔的任意字符串(双引号表示为两个相邻的双引号)。
以下一个或多个符号:
符号/字符
备注
.
(句点)在固定数字模型中,当跟随
0
、9
或X
时作为格式元素处理;否则保持原样。,
(逗号)在数字模型中,当跟随
0
、9
或X
时作为格式元素处理;否则保持原样。;
(分号)始终保持原样。
:
(冒号)始终保持原样。
-
(减号)始终保持原样。
=
(等号)始终保持原样。
/
(正斜杠)始终保持原样。
(
(左括号)始终保持原样。
)
(右括号)始终保持原样。
字面量始终按原样打印,位置与格式模型中的位置完全一致。
下面是一个使用 SQL 格式模型在数字之后(而不是数字之前)打印减号的简短示例。 如果数字是负数,则 MI
指明了减号的位置。
select to_varchar(-123.45, '999.99MI') as EXAMPLE;
输出结果将类似于 123.45-
而不是默认的 -123.45
。
本主题末尾包含更多示例。
格式修饰符和通用空格处理¶
下表列出了控制打印和匹配输入文本的特殊格式元素,这些元素对于所有格式模型都是通用的:
元素 |
描述 |
---|---|
|
不输出任何内容;输入时可选择空格。 |
|
填充模式修饰符;对模型中该修饰符之后的任意元素,可在 紧凑 和 填充 模式之间切换。 |
|
精确匹配修饰符;对模型中该修饰符之后的任意元素,可在 宽松 和 精确 匹配模式之间切换。 |
备注
填充模式修饰符对最小文本数字格式元素(TM
、TM9
和 TME
)没有影响。
使用填充模式修饰符打印输出字符串¶
默认情况下,填充模式设置为 填充,FM
填充模式修饰符将其切换为 紧凑;重复使用可将其切换回 填充,依此类推。
大多数情况下,在打印时使用 填充 模式可以保证格式元素生成固定宽度的输出,具体方法是:在数字左侧用前导零或空格进行填充,在文本右侧用空格进行填充。这样可以保证对齐固定宽度字体的列式输出。
在 紧凑 模式下,大多数格式元素仅生成最小宽度的输出(即,禁止显示前导零和空格以及末尾空格)。
下面明确指出了不遵守这些规则的格式元素。
精确匹配修饰符 FX
不影响打印;下划线格式元素不打印任何内容。
使用修饰符解析输入字符串¶
输入字符串的解析受填充模式修饰符 FM
和完全匹配修饰符 FX
的影响。初始情况:
填充模式设置为 填充,
FM
将其切换到 紧凑 再切换回 填充。精确匹配模式设置为 宽松,
FX
将其切换到 精确 再切换回 宽松。
解析过程中,所有针对格式元素和字面量的字符串匹配都不区分大小写。
在 宽松 模式下,输入解析的第一步是跳过前导空格(空格、制表符、LF、CR、FF 和 VT 字符的序列);如果第一个格式元素是 FX
,则开始输入时的模式为严格,否则为 宽松。
备注
在要解析的值 中,只允许使用普通空格字符(即,组件不能位于不同的行,不能用制表符分隔等)。
在 宽松 匹配模式下,字面量中的空格与任意非空的空格输入序列进行匹配;非空格字符一一匹配。在 精确 模式下,字面量中的所有字符必须与输入字符一一匹配。
数字格式元素与相应的数字序列匹配:
如果同时使用 填充 模式和 精确 模式,则位数必须与相应数字格式元素的宽度完全对应(可添加前导零)。
如果使用 紧凑 模式或 宽松 模式,则匹配的输入数字的位数最多必须等于格式元素的最大宽度,且至少有一位数字;前导零将被忽略。
文本格式元素的匹配不区分大小写:
如果同时使用 填充 模式和 精确 模式,则可使用末尾空格,其数量不超过元素的最大宽度。
否则,在 宽松 模式下,变量长度文本元素后面的空格将被忽略,而在 精确 模式下应与实际单词完全匹配(不带填充空格)。
最后,如果当前模式为 宽松,则输入字符串末尾的空格将被忽略。
通常情况下,如果格式模型中不存在空格,或者在 填充 模式下打印格式元素的内容时无法生成空格,那么 宽松 模式和 精确 模式都不允许匹配空格。
备注
此行为不同于 Oracle 宽松匹配语义,后者可以在任意两个格式元素之间插入空格。Snowflake 使用更严格的匹配语义来避免在自动数据类型识别过程中出现过多的错误匹配。
在 宽松 模式和 精确 模式下,对于出现空格而应忽略空格的位置,可以使用 _
(下划线)格式元素显式标记。
根据经验,精确 模式下的格式仅识别以相同格式打印的输入字符串,而 宽松 模式下的格式则可识别由添加或删除了任何填充模式修饰符的类似格式打印的输入字符串。
数字格式模型¶
数字格式模型支持两种类型:
固定位置(在放置
0
、9
或X
格式元素的位置显式放置数字)最小文本(
TM
、TME
和TM9
格式元素)
备注
这两种类型不能在同一模型中混合使用。
固定位置数字格式¶
备注
本节讨论的是非负固定位置数字;有关固定位置数字格式的输出中数字符号位置的更多信息,请参阅 固定位置格式的符号位置。
固定位置数字使用数字元素 0
或 9
表示。例如,999
包含 1 到 3 位十进制数字。数字的小数部分使用分隔符元素 .
(句点)或 D
进行分隔:
.
始终显示为句点。若要对
D
元素使用不同的字符,请在应用 cast 函数之前修改输入字符串,将所有句点替换为逗号,将所有逗号替换为句点。
通常情况下,整数部分的前导零和小数部分的末尾零将替换为空格(除非整数部分的值为零,在这种情况下会显示为单个 0
字符)。要阻止此行为,请使用 0
格式元素代替 9
;相应位置将保留 0
字符。 格式元素 B
在数字之前使用时,会阻止保留整数值中的最后一个 0
(即,如果您使用 B
并且数字的整数部分的值为零,则所有数字都显示为空格)。
如果数字足够大,则使用数字组分隔符 ,
(逗号)或 G
会导致打印相应的组分隔符字符,以便数字位于组分隔符的两侧。可用于打印货币总和的格式模型示例是 999,999.00
。
当数字整数部分的位数多于格式中的数字位置时,所有位数都打印为 #
以表示溢出。
指数元素会将固定位置的数字标准化,以便整数部分的第一个数字是 1 到 9(除非数字的值为零,在这种情况下,指数的值也为零)。EE
元素会自动选择指数中的正确位数,并且不打印 +
号,而 EEE
、EEEE
和 EEEEE
始终打印指数的 +
号或 -
号以及请求的位数(前导零不会被禁止显示)。指数溢出用 #
代替数字表示。
指数指示符根据格式元素中第一个字母的大小写,打印大写 E
或小写 e
。
X
格式元素的工作原理与 9
类似,只是打印的是十六进制数字 0-9A-F
。目前,不支持十六进制分数。与 9
类似,X
用空格替换前导零。当与 X
一起使用时,0
元素打印的十六进制数不会禁止显示前导零(因此,可使用 000X
打印始终包含 4 位数字的十六进制数字)。
请注意,X
打印十六进制数字时使用大写拉丁字母,而小写 x
打印的是小写拉丁字母。十六进制 0
格式元素使用后续 X
格式元素的大小写。
通常情况下,十六进制数以无符号形式打印,即负数的最有效位全部为 1
,但将 X
元素与显式符号(S
或 MI
)一起使用时 -
符号将与数字的绝对值一起打印。
固定位置数字格式模型会报告浮点数的特殊值(无穷大或非数字)的溢出。
固定位置格式元素¶
下表列出了固定位置格式支持的元素。请注意以下事项:
可重复 列指示元素是否可以在格式模型中重复,否则该元素在每个格式模型中只能使用一次。
区分大小写 列指示元素的大小写会影响其格式。例如:
EE
处理带有大写字母E
的指数。ee
处理带有小写字母e
的指数。
所有其他元素都不区分大小写。
元素 |
可重复 |
区分大小写 |
描述 |
---|---|---|---|
|
美元符号打印在数字之前(通常在符号之后)。 |
||
|
小数分隔符;始终打印为句点。 |
||
|
✔ |
数字组分隔符;打印为逗号或空格。 |
|
|
✔ |
数字的位置;显式打印前导零/末尾零。 |
|
|
✔ |
数字的位置;前导零/末尾零替换为空格。 |
|
|
在随后的数字中用空格表示零值。 |
||
|
小数分隔符; |
||
|
✔ |
可变宽度指数,2 到 5 个字符,整数不带 |
|
|
✔ |
固定宽度指数(3 个字符);范围从 |
|
|
✔ |
固定宽度指数(4 个字符);范围从 |
|
|
✔ |
固定宽度指数(5 个字符);范围从 |
|
|
✔ |
数字组分隔符; |
|
|
显式数字符号占位符;对于正数打印空格,对于负数打印 |
||
|
显式数字符号占位符;对于正数打印 |
||
|
✔ |
✔ |
十六进制数字。 |
固定位置格式的符号位置¶
默认情况下,固定位置格式始终为数字符号保留空间:
对于非负数,默认空格打印在第一位数字之前。
对于负数,默认空格和
-
号打印在第一位数字(或当B
格式元素用于小数时打印在小数)之前。
但是,可以使用 S
、MI
和 $
格式元素来显式指定数字的符号和/或空格所在的位置。
例如(以下示例使用下划线 _
来指示空格的插入位置):
格式模型 |
|
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
使用固定位置格式和填充模式修饰符打印数字¶
在 填充 模式下,可变长度格式元素(如 EE
和 MI
)在右侧填充空格。
在 紧凑 模式下,数字格式元素(包括可变长度元素)产生的所有空格都会被删除,因此生成的字符串更短且不再对齐。例如(注意缺少空格):
格式模型 |
|
|
---|---|---|
|
|
|
使用固定位置格式和修饰符解析数字¶
解析包含数字的字符串会受到 FX
和 FM
修饰符的影响:
在 宽松 模式下:
数字组分隔符是可选的(即,带或不带组分隔符的数字均可匹配,但各个组分隔符之间的位数必须匹配);该模式还允许
+
作为MI
格式元素的有效匹配。宽松 模式不会禁用必须存在数字(甚至是前导零或末尾零)才能匹配
0
格式元素的要求。在 宽松 模式下,前导符号和第一位数字之间的空格是允许的。
此外,在 宽松 模式下,所有指数格式元素(
EE
、EEE
、EEEE
和EEEEE
)都被视为EE
,并与包含 1 至 3 位数字和可选+
号或-
号的指数规范相匹配。使用
B
可匹配整数部分没有数字的数字。在 宽松 模式下,空的小数部分前的小数点是可选的。
在 精确 模式下:
数字必须有适当数量的空格来代替省略的数字以匹配格式(即,在 填充 模式下是空格,而在 紧凑 模式下是缺少空格)。
在 精确 模式下不允许省略组分隔符,并且
MI
不会与+
号匹配。除
EE
外,指数格式元素必须与符号位置和格式元素所需的确切位数匹配。小数点必须位于格式模式指定的位置。
最小文本数字格式¶
虽然固定位置数字格式模型始终显式指定位数,但最小文本格式元素根据数字的值使用最少的位数。TM*
格式元素始终生成不带空格的可变长度输出,而不考虑填充模式修饰符(填充 或 紧凑)。
TM9
根据数字的值将数字打印为整数或小数。任何小数定点数值都会精确打印,小数部分的位数由数字比例决定(在 填充 模式下保留末尾零)。对于浮点数,
TM9
根据数字的指数来选择小数位数(请注意,无法将二进制分数精确转换为十进制分数)。如果浮点数的幅度过大,导致以位置记数法表示时过长,则将切换为以科学记数法表示(见下文TME
)。如果浮点数过小,则TM9
将打印零。TME
以科学记数法打印数字,即带有指数(与EE
相同),并在小数部分的整数位置打印一位数字。指数指示符(E
或e
)的大小写与格式元素中第一个字母(T
或t
)的大小写匹配。TM
根据数字的大小来选择TM9
或TME
,以便在保持精度的同时尽量减少文本长度。
最小文本格式元素¶
下表列出了最小文本格式支持的元素。请注意以下事项:
最小文本格式字符串中的任何元素都不能重复。
区分大小写 列指示元素的大小写会影响其格式。例如:
TME
处理带有大写字母E
的指数。tme
处理带有小写字母e
的指数。
所有其他元素都不区分大小写。
元素 |
可重复 |
区分大小写 |
描述 |
---|---|---|---|
|
美元符号插入在数字之前(通常在符号之后)。 |
||
|
✔ |
最小文本数字,取 |
|
|
✔ |
位置表示法中的最小文本数字。 |
|
|
✔ |
以科学记数法表示的最小文本数字(带指数)。 |
|
|
在随后的数字中用空格表示零值。 |
||
|
显式数字符号占位符;变为 |
||
|
显式数字符号占位符;变为 |
最小文本格式的符号位置¶
默认情况下,最小文本格式的符号为以下之一:
$
、S
和 MI
元素的作用与固定位置格式模型相同。请注意,浮点数有两个不同的零值(+0.
和 -0.
),分别表示无穷小的正值和负值。
使用最小文本格式和修饰符解析数字¶
使用最小文本格式模型进行解析不受 FX
或 FM
修饰符的影响;但是,如上文所述,显式符号元素 S
和 MI
会受到影响。
TM9
匹配以位置计数法表示的十进制数字(整数或小数),但不匹配以科学记数法表示的数字(即带有指数)。相反:
TME
仅匹配科学记数法。TM
两者皆可匹配。
与最小文本元素匹配的数字不能包含空格或数字组分隔符。
指数元素和十六进制数字中的字母始终匹配,而不考虑小写或大写。
备选格式、自动格式和默认格式¶
元素 |
描述 |
---|---|
|
分隔备选格式。 |
|
自动格式。 |
解析字符串时,可以使用 |
字符将格式字符串分隔开来,从而指定多种备选格式。如果字符串与任意一种格式匹配,则可成功解析。如果输入字符串与多种格式匹配,则将使用任意一种格式进行转换。
用于解析的整个格式可以用关键字 AUTO
代替;这将根据源值或结果值的类型插入一个或多个备选自动格式。在自动格式中添加自定义格式时,可以使用 AUTO
作为备选项之一。
当 CAST 函数中未显式指定格式时,将使用默认格式来解析输入值(即在 CSV 文件中)和打印结果。
默认打印格式¶
下表列出了打印的默认格式:
SQL 数据类型 |
参数 |
默认格式 |
---|---|---|
DECIMAL |
无 |
|
DOUBLE |
无 |
|
默认解析格式¶
下表列出了解析的默认格式:
SQL 数据类型 |
参数 |
默认 |
---|---|---|
DECIMAL |
无 |
|
DOUBLE |
无 |
|
用于自动乐观字符串转换(即能够被自动识别为数字的字符串)的格式列表是上述默认输入格式表中所有格式的总和。
示例¶
输出示例¶
此示例演示如何显示带有前导零的数字:
create table sample_numbers (f float); insert into sample_numbers (f) values (1.2); insert into sample_numbers (f) values (123.456); insert into sample_numbers (f) values (1234.56); insert into sample_numbers (f) values (-123456.789); select to_varchar(f, '999,999.999'), to_varchar(f, 'S000,000.000') from sample_numbers;
输出类似以下内容:
+------------------------------+-------------------------------+ | TO_VARCHAR(F, '999,999.999') | TO_VARCHAR(F, 'S000,000.000') | +==============================+===============================+ | 1.2 | +000,001.200 | +------------------------------+-------------------------------+ | 123.456 | +000,123.456 | +------------------------------+-------------------------------+ | 1,234.56 | +001,234.560 | +------------------------------+-------------------------------+ | -123,456.789 | -123,456.789 | +------------------------------+-------------------------------+
您不需要前导零来对齐数字。默认的填充模式为“填充”,这意味着系统将根据小数点的位置,使用前导空格来对齐数字。
select to_varchar(f, '999,999.999'), to_varchar(f, 'S999,999.999') from sample_numbers;
输出类似以下内容:
+------------------------------+-------------------------------+ | TO_VARCHAR(F, '999,999.999') | TO_VARCHAR(F, 'S999,999.999') | +==============================+===============================+ | 1.2 | +1.2 | +------------------------------+-------------------------------+ | 123.456 | +123.456 | +------------------------------+-------------------------------+ | 1,234.56 | +1,234.56 | +------------------------------+-------------------------------+ | -123,456.789 | -123,456.789 | +------------------------------+-------------------------------+
此示例显示如果使用 FM (填充模式)修饰符从“填充”模式切换到“紧凑”模式(即删除用于对齐数字的前导字符),会发生什么情况:
select to_varchar(f, '999,999.999'), to_varchar(f, 'FM999,999.999') from sample_numbers;
输出类似以下内容:
+------------------------------+--------------------------------+ | TO_VARCHAR(F, '999,999.999') | TO_VARCHAR(F, 'FM999,999.999') | +==============================+================================+ | 1.2 | 1.2 | +------------------------------+--------------------------------+ | 123.456 | 123.456 | +------------------------------+--------------------------------+ | 1,234.56 | 1,234.56 | +------------------------------+--------------------------------+ | -123,456.789 | -123,456.789 | +------------------------------+--------------------------------+
此示例演示如何以指数表示法显示数字:
select to_char(1234, '9d999EE'), 'will look like', '1.234E3';
输出类似以下内容:
+--------------------------+------------------+-----------+ | TO_CHAR(1234, '9D999EE') | 'WILL LOOK LIKE' | '1.234E3' | +==========================+==================+===========+ | 1.234E3 | will look like | 1.234E3 | +--------------------------+------------------+-----------+
此示例显示了如何在输出中包含字面量。 字面量部分括在双引号内(而双引号又位于将字符串分隔开来的单引号内)。
select to_char(12, '">"99"<"');
输出类似以下内容:
+-------+ | > 12< | +-------+
输入示例¶
这些示例演示了对输入使用格式模型。
以下示例演示了一些简单的输入操作,重点显示使用“0”和“9”指定数字格式之间的区别。
作为格式标识符的数字“9”将接受空白或“缺失的”前导数字。作为格式标识符的数字“0”不接受空白或缺失的前导零。
-- All of the following convert the input to the number 12,345.67. SELECT TO_NUMBER('012,345.67', '999,999.99', 8, 2); SELECT TO_NUMBER('12,345.67', '999,999.99', 8, 2); SELECT TO_NUMBER(' 12,345.67', '999,999.99', 8, 2); -- The first of the following works, but the others will not convert. -- (They are not supposed to convert, so "failure" is correct.) SELECT TO_NUMBER('012,345.67', '000,000.00', 8, 2); SELECT TO_NUMBER('12,345.67', '000,000.00', 8, 2); SELECT TO_NUMBER(' 12,345.67', '000,000.00', 8, 2);此示例显示了如何接受两种数字格式(
-###
或###-
)之一。-- Create the table and insert data. create table format1 (v varchar, i integer); insert into format1 (v) values ('-101'); insert into format1 (v) values ('102-'); insert into format1 (v) values ('103'); -- Try to convert varchar to integer without a -- format model. This fails (as expected) -- with a message similar to: -- "Numeric value '102-' is not recognized" update format1 set i = TO_NUMBER(v); -- Now try again with a format specifier that allows the minus sign -- to be at either the beginning or the end of the number. -- Note the use of the vertical bar ("|") to indicate that -- either format is acceptable. update format1 set i = TO_NUMBER(v, 'MI999|999MI'); select i from format1;