如何处理此字符串?
Posted
技术标签:
【中文标题】如何处理此字符串?【英文标题】:How do I Process This String? 【发布时间】:2019-05-03 02:51:02 【问题描述】:我的一张表中有一些结果,但结果各不相同;代表我需要拆分的一列中的多个条目。
这是我的 SQL 和结果:
select REGEXP_COUNT(value,';') as cnt,
description
from mytable;
1 Managed By|xBossxBoss xBoss Number|X0910505569Time
Requested|2009-04-15 20:47:11.0Time Arrived|2009-04-15 21:46:11.0;
1 Managed By|Modern ManagementxBoss Number|Time Requested|2009-04-
16 14:01:29.0Time Arrived|2009-04-16 14:44:11.0;
2 Managed By|xBossxBoss Number|X091480092Time Requested|2009-05-28
08:58:41.0Time Arrived|;Managed By|Jims AllocationxBoss xBoss
Number|Time Requested|Time Arrived|;
期望的输出:
R1:
Managed By: xBoss
Time Requested:2009-10-19 07:53:45.0
Time Arrived: 2009-10-19 07:54:46.0
R2:
Managed By:Own Arrangements
Number: x5876523
Time Requested: 2009-10-19 07:57:46.0
Time Arrived:
R3:
Managed By: xBoss
Time Requested:2009-10-19 08:07:27.0
select
SPLIT_PART(description, '', 1),
SPLIT_PART(description, '', 2),
SPLIT_PART(description, '', 3),
SPLIT_PART(description, '', 4),
SPLIT_PART(description, '', 5)
as description_with_tag from mytable;
当计数为1
时这没问题,但是当描述中有多个;
时,它不会给我结果。
是否可以根据计数将其放入数组中?
【问题讨论】:
你想要达到什么输出?你想获得Managed By|xBoss
,还是仅仅获得Managed By|xBoss
?或者只是xBoss
?随时编辑您的问题以提供更多详细信息。另外,你为什么在value
中计算分号却显示description
?
John,我只想检索结果 xBoss,Managed By 的术语将始终相同,但 xBoss 会经常更改。分号决定了一个事件有多少事件。 select REGEXP_COUNT(value,';') 将告诉金额。
我还是一头雾水。您能否编辑您的问题以显示您希望每个输入行的输出?请提供多个示例。
这是原始形式的查询结果。 Managed By|xBossNumber|Time Requested|2009-10-19 07:53:45.0Time Arrived|2009-10-19 07:54:46.0;Managed By|Own ArrangementsNumber |x5876523Time Requested|2009-10-19 07:57:46.0Time Arrived|;Managed By|xBossNumber|Time Requested|2009-10-19 08:07:27.0到达时间|;
这就是我想为我的 ETL R1 操作结果的方式 管理人:xBoss 编号:请求时间:2009-10-19 07:53:45.0 到达时间:2009-10-19 07: 54:46.0; R2 管理人:自己的安排编号:x5876523 请求时间:2009-10-19 07:57:46.0 到达时间:; R3 管理人:xBoss 编号:请求时间:2009-10-19 08:07:27.0 到达时间:;
【参考方案1】:
首先,值得指出的是,这种格式的数据无法充分利用 Redshift 可以提供的所有优势。 Amazon Redshift 是一种列式数据库,当数据存储在适当的列中时,它可以提供惊人的性能。但是,从文本字段中选择特定文本总是会表现不佳。
因此,我的主要建议是将数据预处理为正常的行和列,以便 Redshift 可以为您提供最佳功能。
但是,为了回答您的问题,我建议您制作一个标量用户定义函数:
CREATE FUNCTION f_extract_curly (s TEXT, key TEXT)
RETURNS TEXT
STABLE
AS $$
# List of items in brackets
items = s[1:-1].split('')
# Dictionary of Key|Value from items
entries = i.split('|')[0]: i.split('|')[1] for i in items
# Return desired value
return entries.get(key, None)
$$ LANGUAGE plpythonu;
我加载了样本数据:
CREATE TABLE foo (
description TEXT
);
INSERT INTO foo values('Managed By|xBossxBoss xBoss Number|X0910505569Time Requested|2009-04-15 20:47:11.0Time Arrived|2009-04-15 21:46:11.0;');
INSERT INTO foo values('Managed By|Modern ManagementxBoss Number|Time Requested|2009-04-16 14:01:29.0Time Arrived|2009-04-16 14:44:11.0;');
INSERT INTO foo values('Managed By|xBossxBoss Number|X091480092Time Requested|2009-05-28 08:58:41.0Time Arrived|;Managed By|Jims AllocationxBoss xBoss Number|Time Requested|Time Arrived|;');
然后我测试了它:
SELECT
f_extract_curly(description, 'Managed By'),
f_extract_curly(description, 'Time Requested')
FROM foo
得到了结果:
xBoss 2009-04-15 20:47:11.0
Modern Management 2009-04-16 14:01:29.0
xBoss
它不知道如何处理指定了两次相同字段的行(中间有分号)。您没有提供足够的示例输入和输出行,让我无法确定在这种情况下您想要什么,但请随意调整代码以满足您的要求。
【讨论】:
这太棒了!有时我会收到超出范围的错误消息列表索引。请查看 svl_udf_log 了解更多信息如果找不到任何内容,我该如何返回空值? SELECT name, REGEXP_COUNT(sep_val,';'), f_extract_curly(SPLIT_PART(value,';',1),'Managed By'), f_extract_curly(SPLIT_PART(value,';',2 ),'请求的时间') FROM foo;这似乎有效,但我确实得到 [Amazon](500310) Invalid operation: IndexError: list index out of range. 我已经编辑了return
语句,所以如果没有这样的条目,它应该返回None
。我不确定 Redshift 是否将 Python None
转换为 SQL NULL
,所以请测试一下并告诉我们!
太棒了约翰...非常感谢您的帮助! :)【参考方案2】:
Redshift 中没有数组数据类型。有两种选择:
1) 首先split_part
by ';'
,然后为第一个split_part
输出的每个索引分别合并结果,然后split_part
结果通过''
,最后得到你需要的。
2) 创建 Python UDF 并使用 Python 处理这些字符串。我想这是您用例的最佳解决方案。
3) 在 Redshift 之外转换您的数据。从您的数据结构看来,在复制到 Redshift 之前处理它似乎要好得多,将数组取消嵌套成行并将对象中的键提取到列中。
【讨论】:
以上是关于如何处理此字符串?的主要内容,如果未能解决你的问题,请参考以下文章
如何处理此错误:__init__() 有一个意外的关键字参数“book_category”