【问题标题】:How to truncate a string after a specific word?如何在特定单词后截断字符串?
【发布时间】:2020-04-13 12:16:45
【问题描述】:

我有一串数据类型 nvarchar(max) 像这样:

declare @cbCheckdate nvarchar(max) ='
{"request_id":"364202","final_decision":"FAIL","derived_Attribute_1":"PASS|Number of active MFI :1",
"derived_Attribute_4":"PASS|Total Exposure + Applied Amount :53051.0",
"derived_Attribute_3":"PASS|Number of Total Active Institutions :2",
"derived_Attribute_2":"FAIL|Overdue Amount:17984.0","derived_Attribute_5":"PASS|Write off amount:0.0",
"cbResponseMsg":"Final Decision:FAIL || Number of active MFI :1 || Total Exposure + Applied Amount :53051.0 
|| Number of Total Active Institutions :2 || FAILOve'

我需要像下面这样截断上面的字符串:

declare @cbCheckdate nvarchar(max) ='{"request_id":"364202","final_decision":"FAIL","derived_Attribute_1":"PASS|Number of active MFI :1",
"derived_Attribute_4":"PASS|Total Exposure + Applied Amount :53051.0",
"derived_Attribute_3":"PASS|Number of Total Active Institutions :2",
"derived_Attribute_2":"FAIL|Overdue Amount:17984.0","derived_Attribute_5":"PASS|Write off amount:0.0"'

基本上我需要做的是:如果我的字符串包含这个词cbResponseMsg,那么我需要删除这个词和它后面的所有文本。

【问题讨论】:

  • 您的 SQL Server 版本是多少?
  • SQL 2014 版

标签: sql sql-server tsql sql-server-2014 truncate


【解决方案1】:

由于您使用的是 SQL Server 2014 并且还没有内置的 JSON 支持,我可能会为此编写一个小函数:

CREATE OR ALTER FUNCTION dbo.TruncateAfter(@Input NVARCHAR(MAX), @Delimiter NVARCHAR(100))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    DECLARE @Result NVARCHAR(MAX);

    DECLARE @DelimiterPos INT;
    SET  @DelimiterPos = CHARINDEX(@Delimiter, @Input);

    IF (@DelimiterPos > 0)
        SET @Result = TRIM(LEFT(@Input, @DelimiterPos - 1));
    ELSE
        SET @Result = @Input;

    RETURN @Result;
END

现在,您可以使用两个参数调用此函数 - 您的输入和您正在寻找的“分隔符”。如果找到分隔符,则从其位置开始的任何文本都将被截断 - 如果分隔符未出现在输入中,则返回整个输入:

DECLARE @cbCheckdate NVARCHAR(MAX) = N'
{"request_id":"364202","final_decision":"FAIL","derived_Attribute_1":"PASS|Number of active MFI :1",
"derived_Attribute_4":"PASS|Total Exposure + Applied Amount :53051.0",
"derived_Attribute_3":"PASS|Number of Total Active Institutions :2",
"derived_Attribute_2":"FAIL|Overdue Amount:17984.0","derived_Attribute_5":"PASS|Write off amount:0.0",
"cbResponseMsg":"Final Decision:FAIL || Number of active MFI :1 || Total Exposure + Applied Amount :53051.0 
|| Number of Total Active Institutions :2 || FAILOve'

DECLARE @Delimiter NVARCHAR(MAX) = N'cbResponseMsg';

SELECT 
    dbo.TruncateAfter (@cbCheckdate, @Delimiter)

应该返回所需的输出。

【讨论】:

  • 我不会急于在用户定义的标量函数中这样做。它们因性能问题而臭名昭著。
  • @ZoharPeled:据我所知,只要您不在标量函数中“隐藏”任何实际数据访问(使用 SELECT),性能应该不会太高问题。这个存储的函数只对输入参数进行操作,不会做任何“繁重的工作”——所以我很确定它应该没问题
【解决方案2】:

这个输入可能是JSON格式,所以如果你使用SQL Server 2016+,你可以使用JSON_MODIFY()函数从输入JSON中删除cbResponseMsg键:

声明:

DECLARE @cbCheckdate nvarchar(max) = '{
   "request_id":"364202",
   "final_decision":"FAIL",
   "derived_Attribute_1":"PASS|Number of active MFI :1",
   "derived_Attribute_4":"PASS|Total Exposure + Applied Amount :53051.0",
   "derived_Attribute_3":"PASS|Number of Total Active Institutions :2",
   "derived_Attribute_2":"FAIL|Overdue Amount:17984.0",
   "derived_Attribute_5":"PASS|Write off amount:0.0",
   "cbResponseMsg":"Final Decision:FAIL || Number of active MFI :1 || Total Exposure + Applied Amount :53051.0 || Number of Total Active Institutions :2 || FAILOve"
}'

SELECT @cbCheckdate = JSON_MODIFY(@cbCheckdate, '$.cbResponseMsg', NULL)
SELECT @cbCheckdate

结果:

{
   "request_id":"364202",
   "final_decision":"FAIL",
   "derived_Attribute_1":"PASS|Number of active MFI :1",
   "derived_Attribute_4":"PASS|Total Exposure + Applied Amount :53051.0",
   "derived_Attribute_3":"PASS|Number of Total Active Institutions :2",
   "derived_Attribute_2":"FAIL|Overdue Amount:17984.0",
   "derived_Attribute_5":"PASS|Write off amount:0.0"
}

【讨论】:

  • 'JSON_MODIFY' 不是可识别的内置函数名称。
  • @Mar1009 是的,我在回答中提到了这个,在 SQL Server 2016 中引入了 JSON 支持。如果你的文本是有效的 JSON,你可能需要搜索 UDF 来解析这个 JSON 或尝试使用另一种方法,可能基于字符串或 XML 转换。
【解决方案3】:

你可以这样做

set @cbCheckdate = left(@cbCheckdate, CHARINDEX('cbResponseMsg', @cbCheckdate) -2)  select @cbCheckdate

【讨论】:

  • 如果@cbCheckdate 字符串不包含cbResponseMsg,则此方法会不工作 - 在这种情况下,您会得到:@987654324 @
【解决方案4】:

这是一种安全的方法,无需用户定义的函数,使用内置函数stuffcharindexreverselensign

declare @cbCheckdate nvarchar(max) ='
{"request_id":"364202","final_decision":"FAIL","derived_Attribute_1":"PASS|Number of active MFI :1",
"derived_Attribute_4":"PASS|Total Exposure + Applied Amount :53051.0",
"derived_Attribute_3":"PASS|Number of Total Active Institutions :2",
"derived_Attribute_2":"FAIL|Overdue Amount:17984.0","derived_Attribute_5":"PASS|Write off amount:0.0",
"cbResponseMsg":"Final Decision:FAIL || Number of active MFI :1 || Total Exposure + Applied Amount :53051.0 
|| Number of Total Active Institutions :2 || FAILOve';

declare @delimiter nvarchar(100) = '"cbResponseMsg"';

SELECT  REVERSE(
            STUFF(
                REVERSE(@cbCheckdate), 
                1,
                CHARINDEX(REVERSE(@delimiter), REVERSE(@cbCheckdate)) + 
                    LEN(@delimiter) * SIGN(CHARINDEX(@delimiter, @cbCheckdate)),
            '')
        )

从内到外的细分如下:

  • 如果没有找到分隔符,CHARINDEX(@delimiter, @cbCheckdate) 将返回 0,如果在字符串中找到,则返回正整数。
  • SIGN 将返回 001 为正数或(与本例无关)-1 为负数。
  • CHARINDEX(REVERSE(@delimiter), REVERSE(@cbCheckdate)) + LEN(@delimiter) * SIGN(CHARINDEX(@delimiter, @cbCheckdate)) 将返回 0 是没有找到分隔符,或者是一个正整数,表示分隔符开头到字符串结尾之间的字符数。
  • STUFF 函数将一个空字符串放入源字符串,从第一个字符 (1) 开始并替换它作为第三个参数接收的字符数。
  • 最后,由于这一切都是在反转的字符串上完成的,reverse 再一次返回结果,以正确的顺序返回字符串。

【讨论】:

    【解决方案5】:

    你可以试试这个

    SELECT
            CASE
             WHEN @cbCheckdate LIKE '%cbResponseMsg%' THEN LEFT(@cbCheckdate, CHARINDEX('cbResponseMsg', @cbCheckdate)-3)
             ELSE @cbCheckdate
            END
    

    【讨论】:

    • 注意:A case expression does not always short-circuit,这意味着在某些情况下,此代码可能会为left函数抛出错误。
    • 这不是整数的行为吗?将它用于 (var)char 时从未遇到过问题
    • 我不认为数据类型是问题...我只知道它不能保证短路,不知道确切的条件。
    【解决方案6】:

    试试这个简单有效的查询:

    SELECT
        LEFT(@cbCheckdate, CHARINDEX('cbResponseMsg', @cbCheckdate)-3)
    WHERE 
        @cbCheckdate LIKE '%cbResponseMsg%'
    
    UNION ALL
    
    SELECT
        @cbCheckdate
    WHERE 
        @cbCheckdate NOT LIKE '%cbResponseMsg%'
    

    【讨论】:

      猜你喜欢
      • 2013-04-04
      • 2019-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-21
      • 2011-10-02
      • 2019-01-03
      • 1970-01-01
      相关资源
      最近更新 更多