分隔日期分隔的文本字符串
separate a date-delimited text string
我有以下格式的文本字符串:
09/05/2021: La persona seleccionada se encuentra en seguridad 05/09/2021: Se envia un nuevo grupo de candidatos 07/11/2021: El candidato contratado no inicia
所以我想按每个日期将每个评论与字符串分开。我该怎么做?
结果应该如下:
DATE
COMMENT
09/05/2021
La persona seleccionada se encuentra en seguridad
05/09/2021
Se envia un nuevo grupo de candidatos
07/11/2021
El candidato contratado no inicia
我不喜欢依赖于 SPLIT 输出顺序的解决方案,因为手册说明它不能保证是输入顺序。实际上我相信它使用 .NET 下的拆分引擎盖,可能会按顺序输出..
买者自负!
declare @t VARCHAR(200) = '09/05/2021: La persona seleccionada se encuentra en seguridad 05/09/2021: Se envia un nuevo grupo de candidatos 07/11/2021: El candidato contratado no inicia';
WITH x AS (
SELECT
RIGHT(LAG(value) OVER(order by (select null)), 10) as d,
SUBSTRING(value, 2, LEN(value) - CASE WHEN value LIKE '%__/__/____' THEN 11 ELSE 1 END) as t
FROM
string_split(@t, ':')
)
SELECT d, t FROM x WHERE d IS NOT NULL
这会在 :
上拆分,然后从“上一个”值的末尾检索日期,以便与当前值中的文本配对。它会检查末尾是否有日期,然后再决定是将子字符串保留到字符串末尾,还是从字符串末尾返回最多 10 个字符
如果你想在 SQLS 中更安全地执行此操作,你可能会更好地使用递归 CTE 和 SUBSTRING 和 CHARINDEX 逐步查找 ': '
的位置,然后从 10 个字符向上切回到下一个索引。
看起来像这样:
declare @t VARCHAR(200) = '09/05/2021: La persona seleccionada se encuentra en seguridad 05/09/2021: Se envia un nuevo grupo de candidatos 07/11/2021: El candidato contratado no inicia';
WITH x(s, sp, p) as (
SELECT s, 1, CHARINDEX(': ', s) FROM (SELECT @t AS s) xx
UNION ALL
SELECT s, p + 1, CHARINDEX(': ', s, p + 1)
FROM X
WHERE p > 0
)
SELECT
SUBSTRING(s, sp - 11, 10) d,
SUBSTRING(s, sp + 1, CASE WHEN p > 0 THEN p - sp - 12 ELSE LEN(s) END) c
FROM x
WHERE sp > 1
递归 CTE 重复使用 CHARINDEX 查找 ': '
并在每次循环时有效地给出起始位置 (sp) 和结束位置 (p)。本次以上次的位置作为起始位置,递增查找字符串。从这些指数调整到因素可以使用日期,并且类似地用于评论。如果您想查看更多信息,请执行 select * FROM x
用前端语言做会安全很多,比如C#确实保证拆分顺序,这个逻辑类似:
var a = string.Split(": ");
for(int i = 1; i < a.Length - 1; i++)
Console.WriteLine( (a[i-1][^10..], a[i][..^11]) );
Console.WriteLine( (a[^2][^10..], a[^1]) );
此变体在 ": "
上拆分,这是 SQLS 无法做到的,这从一开始就减少了对 trim 无关空间的需求。之后,一个循环处理除最后一行以外的所有内容(它的末尾没有日期,因此必须区别对待)从 1 开始(因此它可以安全地引用前一个元素)。
a[i-1][^10..]
表示 数组 a
,元素字符串位于 i-1
,从末尾开始的子串 10 到从末尾开始的 0,即最后 10 个字符
a[i][..^11]
表示 数组 a
,元素 i
,从开始到结束的 11 个字符的子字符串,即除最后 11 个字符之外的所有字符
a[^2][^10..]
表示 数组 a
,从末尾开始的元素 2,即最后一个,最后 10 个字符
a[^1]
表示数组a
, 的最后一个元素
我有以下格式的文本字符串:
09/05/2021: La persona seleccionada se encuentra en seguridad 05/09/2021: Se envia un nuevo grupo de candidatos 07/11/2021: El candidato contratado no inicia
所以我想按每个日期将每个评论与字符串分开。我该怎么做?
结果应该如下:
DATE | COMMENT |
---|---|
09/05/2021 | La persona seleccionada se encuentra en seguridad |
05/09/2021 | Se envia un nuevo grupo de candidatos |
07/11/2021 | El candidato contratado no inicia |
我不喜欢依赖于 SPLIT 输出顺序的解决方案,因为手册说明它不能保证是输入顺序。实际上我相信它使用 .NET 下的拆分引擎盖,可能会按顺序输出..
买者自负!
declare @t VARCHAR(200) = '09/05/2021: La persona seleccionada se encuentra en seguridad 05/09/2021: Se envia un nuevo grupo de candidatos 07/11/2021: El candidato contratado no inicia';
WITH x AS (
SELECT
RIGHT(LAG(value) OVER(order by (select null)), 10) as d,
SUBSTRING(value, 2, LEN(value) - CASE WHEN value LIKE '%__/__/____' THEN 11 ELSE 1 END) as t
FROM
string_split(@t, ':')
)
SELECT d, t FROM x WHERE d IS NOT NULL
这会在 :
上拆分,然后从“上一个”值的末尾检索日期,以便与当前值中的文本配对。它会检查末尾是否有日期,然后再决定是将子字符串保留到字符串末尾,还是从字符串末尾返回最多 10 个字符
如果你想在 SQLS 中更安全地执行此操作,你可能会更好地使用递归 CTE 和 SUBSTRING 和 CHARINDEX 逐步查找 ': '
的位置,然后从 10 个字符向上切回到下一个索引。
看起来像这样:
declare @t VARCHAR(200) = '09/05/2021: La persona seleccionada se encuentra en seguridad 05/09/2021: Se envia un nuevo grupo de candidatos 07/11/2021: El candidato contratado no inicia';
WITH x(s, sp, p) as (
SELECT s, 1, CHARINDEX(': ', s) FROM (SELECT @t AS s) xx
UNION ALL
SELECT s, p + 1, CHARINDEX(': ', s, p + 1)
FROM X
WHERE p > 0
)
SELECT
SUBSTRING(s, sp - 11, 10) d,
SUBSTRING(s, sp + 1, CASE WHEN p > 0 THEN p - sp - 12 ELSE LEN(s) END) c
FROM x
WHERE sp > 1
递归 CTE 重复使用 CHARINDEX 查找 ': '
并在每次循环时有效地给出起始位置 (sp) 和结束位置 (p)。本次以上次的位置作为起始位置,递增查找字符串。从这些指数调整到因素可以使用日期,并且类似地用于评论。如果您想查看更多信息,请执行 select * FROM x
用前端语言做会安全很多,比如C#确实保证拆分顺序,这个逻辑类似:
var a = string.Split(": ");
for(int i = 1; i < a.Length - 1; i++)
Console.WriteLine( (a[i-1][^10..], a[i][..^11]) );
Console.WriteLine( (a[^2][^10..], a[^1]) );
此变体在 ": "
上拆分,这是 SQLS 无法做到的,这从一开始就减少了对 trim 无关空间的需求。之后,一个循环处理除最后一行以外的所有内容(它的末尾没有日期,因此必须区别对待)从 1 开始(因此它可以安全地引用前一个元素)。
a[i-1][^10..]
表示 数组a
,元素字符串位于i-1
,从末尾开始的子串 10 到从末尾开始的 0,即最后 10 个字符a[i][..^11]
表示 数组a
,元素i
,从开始到结束的 11 个字符的子字符串,即除最后 11 个字符之外的所有字符a[^2][^10..]
表示 数组a
,从末尾开始的元素 2,即最后一个,最后 10 个字符a[^1]
表示数组a
, 的最后一个元素