[英]Convert arbitrary date-like string to date in Teradata
我有一列具有这样的字符串值
12/01/1999 13021999 140301 bla bla 140302 just bla bla
它们具有相对定义格式的日期,可以是带日期的任意文本,也可以是任意文本。
我需要将此数据放在日期数据类型的列中。 我如何在Teradata中做到这一点?
如果在Oracle中,我将编写一些过程来执行某些regexp / replace,然后将结果转换为日期。 当异常返回null时。 然后,我将插入/选择并使用此过程,这是我的日期列。
在Teradata 14.10中,您可以编写SQL用户定义的函数。 但是它只有on语句-返回表达式。 无法像过程中那样进行异常处理和其他语句。
或者,您可以使用C / Java编写外部函数。 然后您必须安装它。 我不确定我的环境中是否拥有此类权利。 另外,我不在C / Java中。
此任务还有其他选择吗?
在Teradata中,有很多方法可以解决这一问题。
您可能会喜欢上存储过程,将光标移过记录集并在那里执行逻辑。 这会很慢,但是逻辑会很干净。
我只是在SQL语句中执行此操作,并喜欢CASE语句逻辑。 我将使用strtok_split_to_table
将每个记录分成单词,然后检查使用正则表达式返回的每个标记以及诸如此类的东西以弄清楚其格式,并尝试基于此转换它。 就像是:
CREATE MULTISET VOLATILE TABLE uglydates
(
id INTEGER,
uglydate VARCHAR(100)
)UNIQUE PRIMARY INDEX ("id") ON COMMIT PRESERVE ROWS;
INSERT INTO uglydates VALUES (1, '12/01/1999');
INSERT INTO uglydates VALUES (2, '13021999');
INSERT INTO uglydates VALUES (3, '140301');
INSERT INTO uglydates VALUES (4, 'bla bla 140302');
INSERT INTO uglydates VALUES (5, 'just bla bla');
SELECT
outkey,
token,
CASE
WHEN REGEXP_SIMILAR(token, '^[0-9,/,-]*$') = 1
THEN /* We've got a date... maybe */
CASE
WHEN "LENGTH"(token) = 10 AND length(OREPLACE(token, '/', '')) = "LENGTH"(token)-2
THEN /* if the formats always the same in this scenario then */
CAST(token AS DATE FORMAT 'mm/dd/yyyy')
WHEN "LENGTH"(token) = 6
THEN
CAST(token AS DATE FORMAT 'yymmdd')
END
ELSE NULL
END
FROM
(
SELECT d.token, d.outkey
FROM TABLE (strtok_split_to_table(uglydates.id, uglydates.uglydate, ' ')
RETURNS (outkey integer, tokennum integer, token varchar(20)character set unicode) ) as d
) tokens
那是一个相当空洞的入门,但是它可以带您正确的方向。 我已经使用strtok_split_to_table
解析丑陋的日期文本,并为每个单词返回一条记录,以及记录的ID,以便以后可以插入/更新而不会丢失该记录的引用。 剩下的就是非常简单的正则表达式,而对于您在Oracle中所做的一切来说,它们应该看起来很熟悉。
上面的示例产生以下输出:
+--------+------------+--------------------+
| outkey | token | <CASE expression> |
+--------+------------+--------------------+
| 5 | just | |
| 3 | 140301 | 2014-03-01 |
| 4 | bla | |
| 1 | 12/01/1999 | 1999-12-01 |
| 2 | 13021999 | |
| 5 | bla | |
| 4 | bla | |
| 5 | bla | |
| 4 | 140302 | 2014-03-02 |
+--------+------------+--------------------+
要将其配对到您关心的日期,可以使用Teradata的QUALIFY
子句,该子句允许您使用窗口函数来过滤结果集。 这类似于在SELECT子句中执行window函数,将结果粘贴在子查询中,并在Window Function结果字段上使用WHERE语句,但是没有所有其他代码。 就像是:
SELECT
outkey,
token,
CASE
WHEN REGEXP_SIMILAR(token, '^[0-9,/,-]*$') = 1
THEN /* We've got a date... maybe */
CASE
WHEN "LENGTH"(token) = 10 AND length(OREPLACE(token, '/', '')) = "LENGTH"(token)-2
THEN /* if the formats always the same in this scenario then */
CAST(token AS DATE FORMAT 'mm/dd/yyyy')
WHEN "LENGTH"(token) = 6
THEN
CAST(token AS DATE FORMAT 'yymmdd')
WHEN "LENGTH"(token) = 8
THEN
CAST(token AS DATE FORMAT 'ddmmyyyy')
ELSE NULL
END
ELSE NULL
END AS outdate
FROM
(
SELECT d.token, d.outkey
FROM TABLE (strtok_split_to_table(uglydates.id, uglydates.uglydate, ' ')
RETURNS (outkey integer, tokennum integer, token varchar(20)character set unicode) ) as d
) tokens
QUALIFY ROW_NUMBER() OVER (PARTITION BY outkey ORDER BY outdate DESC) = 1
它将按出站键对数据进行分区,按我们发现的日期降序排列,然后为每个出站键按该顺序选择第一个记录。 结果集如下所示:
+--------+------------+------------+
| outkey | token | outdate |
+--------+------------+------------+
| 1 | 12/01/1999 | 1999-12-01 |
| 2 | 13021999 | 1999-02-13 |
| 3 | 140301 | 2014-03-01 |
| 4 | 140302 | 2014-03-02 |
| 5 | bla | |
+--------+------------+------------+
这样,您就准备好执行UPDATE语句了。
在SQL语句中完成所有操作的很酷的事情是,您允许Teradata为您优化执行路径。 即使在大桌子上,这也可以非常快地完成,而带有游标的SP(尽管逻辑更容易读取)将非常慢。 而且自定义功能将仅限于单安培处理(我相信即使在15.10中也是如此,对吗?...我不确定是否100%正确),所以即使您有一个正确索引的表且具有良好的性能歪斜您将在盒子的一小部分上操作最详尽的逻辑位。 @dnoeth,请诚实地说。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.