Sql 如何截断特定单词后的字符串?

Sql 如何截断特定单词后的字符串?,sql,sql-server,tsql,sql-server-2014,truncate,Sql,Sql Server,Tsql,Sql Server 2014,Truncate,我有一个数据类型字符串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_

我有一个数据类型字符串
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
,那么我需要删除这个单词及其后面的所有文本。

这个输入可能是JSON格式的,因此如果使用SQL Server 2016+,可以使用
JSON\u 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"
}
你能做到的

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

由于您使用的是SQL Server2014,并且还没有内置的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)

应该返回所需的输出。

这是一种安全的方法,不需要用户定义的函数,使用内置函数
stuff
charindex
reverse
len
sign

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
    对于
    0
    将返回
    0
    ,对于正数将返回
    1
    ,对于负数将返回
    -1
  • CHARINDEX(反向(@delimiter),反向(@cbCheckdate))+
    LEN(@delimiter)*SIGN(CHARINDEX(@delimiter,@cbCheckdate))
    将返回
    0
    如果未找到分隔符,或者是一个正整数,表示分隔符开头到字符串结尾之间的字符数
  • STUFF
    函数将一个空字符串放入源字符串中,从第一个字符(
    1
    )开始,并替换它接受的字符数作为第三个参数
  • 最后,由于这一切都是在反向字符串上完成的,
    reverse
    再次返回结果,以正确的顺序返回字符串
    • 你可以试试这个

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

      将此作为一个简单、有效的查询进行尝试:

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

      您的SQL Server版本是什么?SQL 2014版“JSON_MODIFY”不是公认的内置函数名。@Mar1009是的,我在回答中提到了这一点,SQL Server 2016中引入了JSON支持。如果您的文本是有效的JSON,您可能需要搜索UDF来解析此JSON,或者尝试使用另一种方法,可能基于字符串或XML转换。如果
      @cbCheckdate
      字符串不包含
      cbResponseMsg
      ,则此方法无效-在这种情况下,您会得到:
      Msg 537,级别16,状态3,第3行传递给LEFT或SUBSTRING函数的长度参数无效。
      我不希望在用户定义的标量函数中这样做。它们因性能问题而臭名昭著。@ZoharPeled:据我所知,只要不在标量函数中“隐藏”任何实际的数据访问(使用
      选择
      ),性能就不会真正成为问题。这个存储函数只对输入参数进行操作,不会以这种方式执行任何“繁重的操作”——因此我非常确定它应该是很好的注释:,这意味着在某些情况下,此代码可能会为
      left
      函数抛出错误。这不是整数的行为吗?在将其用于(var)charI时从未出现过问题我不认为数据类型是问题所在。。。我只知道不能保证短路,不知道具体情况。