【问题标题】:BCP CHAR value to Snowflake雪花的 BCP CHAR 值
【发布时间】:2019-11-15 16:27:19
【问题描述】:

我正在尝试使用 | 创建 BCP 文件分隔符,然后将其加载到雪花表中。

问题: 在 SQL Server 中有定义为 CHAR(4) 的列并且具有值“sss” 所以当我做 BCP 时,它被填充到 4“sss”的长度并被加载到雪花中 由于我们的报告失败了,因为它们执行了 where column="SSS" 之类的操作,但由于雪花中的尾随空格,没有显示正确的列。

我们不想更改我们的报告。那么,BCP 有没有办法处理这些列的填充或修剪?

请注意,有 24 个表,每个表大约有 130 多列,所以我不能在每个 char 列上放置 Trim 函数

【问题讨论】:

  • 在 SQL Server、Snowflake 或两者中将类型定义为 varchar(4) 怎么样?
  • 您的问题是BCP文件中没有包含尾随空格,还是Snowflake在加载到Snowflake时正在删除尾随空格?
  • 这是一个问题,因为 Snowflake CHAR 语义与其他数据库不同。
  • 标题应该类似于...“BCP 在加载到 Snowflake 之前向数据添加空格”?

标签: mysql sql padding bcp snowflake-cloud-data-platform


【解决方案1】:

如果您的 BCP 文件保留了尾随空格,那么 Snowflake 也会保留它,只要该字段是 FIELD_OPTIONALLY_ENCLOSED_BY 为“或”。您可能还需要确保您的 TRIM_SPACE 选项在您的格式中正确设置COPY INTO 命令的定义。

如果您的 BCP 文件没有维护空间并且您不知道如何使其工作,您可以在 COPY INTO 命令期间使用 SELECT 中的一些字符串函数强制重新输入空间,或者您可以为您的报表创建一个视图,该视图执行相同的字符串函数集以强制为您的报表工作提供空间。

【讨论】:

  • BCP 正在维护尾随空格,这是应该的。使用 TRIM_SPACE 应该是解决报告问题的好方法。
【解决方案2】:

那么,BCP 有没有办法处理这些列的填充或修剪?

是的,但不是通过某些开关或选项。处理此问题的正确方法是预先设置数据类型。正如您在 cmets 中提到的问题,您创建 BCP 输出的查询应使用 VARCHAR(4) 而不是 CHAR(4)。 BCP 正在为您提供您所要求的。他们避免空格的方法是使用 varchar。

似乎对脚本化查询对象进行相当快速的“查找和替换”可以正常工作,但您最了解自己的情况。

此外,“修剪”不起作用 - 仅供参考。即使该字段的值只是“SSS”(如您的示例);如果结果/列定义为 CHAR(4),您将获得 4 个字节的数据和第 4 位的空白,因为您只有 3 个字节的数据。修剪将在查询期间起作用......您得到的填充“”被复制出来。解决此问题的方法是根据需要预先设置数据类型。

除非有人知道雪花的更好方法(我不熟悉它),否则唯一的其他选择是在 SQL 和雪花之间操作文件。替换“|”用“|”...但是... blech。

【讨论】:

  • 重新定义数据类型可能是小型本土解决方案的一种选择,但不适用于大多数解决方案。你是对的,BCP queryout trim() 可能不起作用(不是没有强制转换为 VARCHAR),但更优雅的解决方法是使用 TRIM_SPACE 选项来复制 INTO,正如 Mike Walton 在他的回答中所建议的那样。
  • 可以使用 DDL 设置数据类型,也可以通过强制转换为实际查询数据的视图/查询来设置数据类型。这可以在本土或企业解决方案中完成。事实上,我发现在企业解决方案中更有可能直接访问源数据。但是同意,如果在目的地有一种快速干净的方法来处理这个问题,那么就这样做。我正在直接解决有关 SQL Server BCP 的海报问题。
【解决方案3】:

这是BCP 的一个已知“问题”。 “解决方案”是使用queryout 选项,这意味着您必须在每次导出时包含一个查询。但数据就是这样。

例如:https://social.msdn.microsoft.com/Forums/sqlserver/en-US/88c258fe-d1a6-4f3a-9dac-40388d04e9c7/remove-space-in-columns-on-bcp-out?forum=transactsql

但这确实是雪花问题,因为雪花有自己默认的CHAR语义。
您会在文档 String & Binary Data Types 中收到警告,但这并不能说明全部真相。

在 Oracle(显然是 MSSQL?MySQL?)上执行的以下命令将选择 aaa 行:

CREATE TABLE C AS SELECT CAST('aaa ' AS CHAR(4)) t FROM DUAL;
SELECT * FROM C WHERE t = 'aaa';

但不会在 Snowflake 上,除非您使用 COLLATION 创建列:

CREATE OR REPLACE TABLE C (t CHAR(4) COLLATE 'en_US-rtrim');
INSERT INTO C VALUES('aaa ');
SELECT * FROM C WHERE t = 'aaa';

不幸的是,您不能在创建后ALTER 排序规则,这在COPY INTO <table> 之后会很方便。

PS: Mike Walton 的回答更好,TRIM_SPACECOLLATE 干净得多。

【讨论】:

  • 这不是 BCP 的“问题”。类型为CHAR()CHAR()s 用空格填充。
  • 我同意,因此我的报价。这是关于 Snowflake 上的默认 CHAR 语义不同。
  • 发帖人的问题不是“aaa”……他的价值是“aaa”。他的问题是他复制出来是强制 4 个字节的数据......而不是数据中实际包含一个额外的字节。当真正的价值是“aaa”而不是“aaa”时,很难在这里指责雪花。这是一个分隔文件...不需要固定宽度的字段。
  • 两个数据库中的值相同,即'aaa'。两个数据库的行为不同,比较 'aaa' = 'aaa' 在原始数据库中返回 TRUE,但在 Snowflake 中返回 FALSE。但是在为 Snowflake 列配置 COLLATE 时,'aaa' = 'aaa' 在 Snowflake 中也返回 TRUE。第二种选择是在导入 Snowflake 时修剪字符串,希望这不会破坏其他内容。
  • 原始海报状态...有值“sss”所以当我做 BCP 时,它被填充到 4 个“sss”的长度......源数据库只有 3 个字节的数据。第4次是由副本介绍出来的。正如你所说,这两个数据库的行为确实不同......我没有解决这个问题。只是想强调由于数据类型的选择而引入字节的是复制输出。数据本身很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 1970-01-01
  • 2021-10-15
相关资源
最近更新 更多