分隔日期分隔的文本字符串

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
  • 的最后一个元素