从包含 json 个对象且没有分隔符的文件中加载数据
Load data from a file containing json objects without a delimiter
我正在尝试将数据从 s3 中的文件加载到雪花中。由于我无法控制的原因,这些文件的内容是没有分隔符的 JSON 对象,例如,单个文件将是这样的:
{"key1":"valueA","key2":"valueB"}{"key1":"valueC","key2":"valueD"}
所以我无法创建带有任何分隔符的文件格式。我有一个使用 '}{'
然后用缺少的括号包装两个记录(JSON 对象)的想法,但是没有这样的选项并且记录分隔符接受单个字符。另一种方法可能是使用正则表达式来捕获单个记录,但我在文档中没有看到任何内容。
有没有更好的方法来处理这个问题?
由于整个文件无效JSON,您无法将其作为半结构化数据读取。
如果对象在内部 }
个字符处拆分,您可以将文件读取为 CSV 文件并巧妙地重新组合:
CREATE OR REPLACE TABLE T (
LINE_NO NUMBER IDENTITY,
JSON TEXT
);
COPY INTO T(JSON) FROM (SELECT ||'}' JSON FROM @my_stage/json.csv)
FILE_FORMAT = (TYPE = CSV FIELD_DELIMITER = NONE RECORD_DELIMITER='}');
SELECT REC_NO, PARSE_JSON(LISTAGG(JSON) WITHIN GROUP (ORDER BY LINE_NO)) JSON FROM (
SELECT
SUM(CASE WHEN NEW_OBJ AND MOD(QUOTE_QTY_AGG - QUOTE_QTY, 2) = 0 THEN 1 ELSE 0 END)
OVER (ORDER BY LINE_NO) REC_NO, LINE_NO, JSON
FROM (
SELECT
REGEXP_COUNT(JSON, '"') - REGEXP_COUNT(JSON, '\\"') QUOTE_QTY,
SUM(REGEXP_COUNT(JSON, '"') - REGEXP_COUNT(JSON, '\\"'))
OVER (ORDER BY LINE_NO) QUOTE_QTY_AGG,
REGEXP_LIKE(JSON, '\s*\{\s*".*') NEW_OBJ,
LINE_NO, JSON
FROM T
)
)
GROUP BY REC_NO
ORDER BY REC_NO;
上面的查询将(在这里伸出我的头)解析 any "valid"(模多个对象)JSON,甚至像 [=12 这样的对象=].它通过观察以下内容来做到这一点:
- 新对象以
{"
开头,但如果 {
位于字符串 中则不是
- 如果前几行中未转义的双引号字符的数量是偶数,则当前行的开头不在字符串中
Hans 的方法可以奏效,但它是一个相当(不错!)的 hack。
有一个更简单的方法如果您的文件不是太大(最多几兆字节)。
然后您可以将整个文件作为单个 varchar
值读取,然后 post 使用如下所示的方式对其进行处理。简而言之,我们
- 将字符串拆分为
}{
- "fix" 如果需要,缺少的卷发
parse_json
结果:
代码如下:
create or replace table x(v varchar) as
select * from values('{"a":1}{"b":2}{"c":{"cc":3}}');
select parse_json(
concat(
iff(startswith(spl.value,'{'), '', '{'), -- add '{' if needed
spl.value,
iff(endswith(spl.value, '}'), '', '}') -- add '}' if needed
)
) rec
from x, lateral split_to_table(v, '}{') spl;
-------------+
REC |
-------------+
{ |
"a": 1 |
} |
{ |
"b": 2 |
} |
{ |
"c": { |
"cc": 3 |
} |
} |
-------------+
我正在尝试将数据从 s3 中的文件加载到雪花中。由于我无法控制的原因,这些文件的内容是没有分隔符的 JSON 对象,例如,单个文件将是这样的:
{"key1":"valueA","key2":"valueB"}{"key1":"valueC","key2":"valueD"}
所以我无法创建带有任何分隔符的文件格式。我有一个使用 '}{'
然后用缺少的括号包装两个记录(JSON 对象)的想法,但是没有这样的选项并且记录分隔符接受单个字符。另一种方法可能是使用正则表达式来捕获单个记录,但我在文档中没有看到任何内容。
有没有更好的方法来处理这个问题?
由于整个文件无效JSON,您无法将其作为半结构化数据读取。
如果对象在内部 }
个字符处拆分,您可以将文件读取为 CSV 文件并巧妙地重新组合:
CREATE OR REPLACE TABLE T (
LINE_NO NUMBER IDENTITY,
JSON TEXT
);
COPY INTO T(JSON) FROM (SELECT ||'}' JSON FROM @my_stage/json.csv)
FILE_FORMAT = (TYPE = CSV FIELD_DELIMITER = NONE RECORD_DELIMITER='}');
SELECT REC_NO, PARSE_JSON(LISTAGG(JSON) WITHIN GROUP (ORDER BY LINE_NO)) JSON FROM (
SELECT
SUM(CASE WHEN NEW_OBJ AND MOD(QUOTE_QTY_AGG - QUOTE_QTY, 2) = 0 THEN 1 ELSE 0 END)
OVER (ORDER BY LINE_NO) REC_NO, LINE_NO, JSON
FROM (
SELECT
REGEXP_COUNT(JSON, '"') - REGEXP_COUNT(JSON, '\\"') QUOTE_QTY,
SUM(REGEXP_COUNT(JSON, '"') - REGEXP_COUNT(JSON, '\\"'))
OVER (ORDER BY LINE_NO) QUOTE_QTY_AGG,
REGEXP_LIKE(JSON, '\s*\{\s*".*') NEW_OBJ,
LINE_NO, JSON
FROM T
)
)
GROUP BY REC_NO
ORDER BY REC_NO;
上面的查询将(在这里伸出我的头)解析 any "valid"(模多个对象)JSON,甚至像 [=12 这样的对象=].它通过观察以下内容来做到这一点:
- 新对象以
{"
开头,但如果{
位于字符串 中则不是
- 如果前几行中未转义的双引号字符的数量是偶数,则当前行的开头不在字符串中
Hans 的方法可以奏效,但它是一个相当(不错!)的 hack。
有一个更简单的方法如果您的文件不是太大(最多几兆字节)。
然后您可以将整个文件作为单个 varchar
值读取,然后 post 使用如下所示的方式对其进行处理。简而言之,我们
- 将字符串拆分为
}{
- "fix" 如果需要,缺少的卷发
parse_json
结果:
代码如下:
create or replace table x(v varchar) as
select * from values('{"a":1}{"b":2}{"c":{"cc":3}}');
select parse_json(
concat(
iff(startswith(spl.value,'{'), '', '{'), -- add '{' if needed
spl.value,
iff(endswith(spl.value, '}'), '', '}') -- add '}' if needed
)
) rec
from x, lateral split_to_table(v, '}{') spl;
-------------+
REC |
-------------+
{ |
"a": 1 |
} |
{ |
"b": 2 |
} |
{ |
"c": { |
"cc": 3 |
} |
} |
-------------+