sql:检查子字符串是否为数字并替换它

时间:2017-03-22 10:45:46

标签: sql sql-server json substring

在我的表格中,我有一个包含json

的列
{
    "field1": "value1",
    "block1": {
        "aaa": "string",
        "bb": "1234567890"
    }
}

如何编写一个sql查询来检查bb字段的值是否为数字,如果是,请将其替换为字符串?

结果如下:

{
    "field1": "value1",
    "block1": {
        "aaa": "string",
        "bb": "xxxxxxxxxx"
    }
}

请注意,json可能包含block1之前的其他块。

我正在使用SQL server 2014

2 个答案:

答案 0 :(得分:0)

发现这是一项具有挑战性的任务,所以这里有:

首先,创建一个返回bb:

值的函数
CREATE FUNCTION fn_getBB(@str NVARCHAR(1000))
RETURNS NVARCHAR(1000)
AS
BEGIN
DECLARE @ret NVARCHAR(1000)
SELECT @ret = (LEFT(RIGHT(@str,len(@str) - CHARINDEX('"bb": ', @str) - 6),        CHARINDEX('"',RIGHT(@str,len(@str) - CHARINDEX('"bb": ', @str) - 7),2)))
RETURN @ret;
END

没有它可以做到,但至少可以说它变得难以理解。

之后,您可以像这样测试:

DECLARE @str nvarchar(1000)
SET @str = 'whatevertexthere "bb": "1237777" whateverothertextherexxx'

SELECT REPLACE(@str, '"bb": "'+dbo.fn_getBB(@str)+'"','"bb": "'+ 'ana are mere"')
WHERE ISNUMERIC(dbo.fn_getBB(@str)) = 1

如果测试看起来不错,只需在桌面上使用相同的UPDATE子句(WHERE)运行WHERE ISNUMERIC(dbo.fn_getBB(@str)) = 1

希望它有所帮助!

PS - 该函数假定您的JSON中始终存在“bb”。如果情况并非如此,您可以随时将其作为WHERE子句中的条件提供。

PPS - 如果您不想更新表格,只需在结果集中替换bb的值,请使用SELECT CASE WHEN ISNUMERIC(fn_getBB(yourjsoncol)) = 1 THEN REPLACE ... ELSE yourjsoncol ...

答案 1 :(得分:0)

以下查询非常冗长,因为它包含用于演示查询工作的外部select语句中的各种字段。要获得有效的查询,select语句只需要最右边的列(即CASE ... END语句)。

目标

  

编写一个SQL查询,检查bb字段的值是否为数字,如果是,则将其替换为字符串。

SQL查询

下面外部查询中的每一列都显示了实现目标的渐进步骤,下面将解释这些步骤。

注意:要获得有效的查询,select语句只需要最右边的列(即CASE ... END语句)。所有其他列都不是必需的。

SELECT 
    json 
  -- Find the position of the JSON tag "bb": " 
  , PATINDEX(jsontagpattern, json) 
  -- Return the JSON data to the right of the JSON tag (right-half of the JSON) 
  , RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1) 
  -- Find the first double-quote from the right-half of the JSON 
  , PATINDEX(
        '%"%', 
        RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1)
    ) 
  -- Return the value of the JSON tag "bb" based on the position of the double-quote found above 
  , LEFT(
        RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1), 
        PATINDEX(
            '%"%', 
            RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1) 
        ) - 1 
    ) 
  -- Check if the above value is numeric or not 
  , ISNUMERIC( 
        LEFT(
            RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1), 
            PATINDEX('%"%', RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1)) - 1 
        )
    ) 
  -- Note: Only the following CASE expression is required, the previous expressions above were only to demonstrate the workings of the query 
  , CASE WHEN 
      ISNUMERIC( 
        LEFT(
            RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1), 
            PATINDEX('%"%', RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1)) - 1 
        )
      ) = 1 
    THEN 
      -- The value is numeric, replace the value with 'replacetext' 
      STUFF(
        json, 
        PATINDEX(jsontagpattern, json) + jsontaglength, 
        LEN( 
          LEFT(
              RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1), 
              PATINDEX('%"%', RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1)) - 1 
          )
        ), 
        replacetext
      ) 
    ELSE json 
    END as OutputJson 
FROM ( 
  -- Sample data for demonstration purposes 
  -- Two JSON blocks, one where the field bb is numeric, one where it is not 
    SELECT 
    '{
        "field1": "value1",
        "block1": {
            "aaa": "string",
            "bb": "1234567890"
        }
    }' AS json 
    -- This expression is the string 
    -- %"bb": " 
    -- and is used for pattern matching 
    , '%' + '"bb": "' + '%' AS jsontagpattern 
    -- The length of the string used in pattern matching 
    , LEN(  '"bb": "'     ) AS jsontaglength 
    -- If the value of bb is numeric, replace it with the following text 
    , 'XXXX'                AS replacetext 
    UNION 
    SELECT 
    '{
        "field1": "value1",
        "block1": {
            "aaa": "string",
            "bb": "1a23456789b0"
        }
    }' AS json 
    , '%' + '"bb": "' + '%' AS jsontagpattern 
    , LEN(  '"bb": "'     ) AS jsontaglength 
    , 'XXXX'                AS replacetext 
  ) AS x 

解释

  1. 第一步是找到bb标记的位置。这是由PATINDEX() function

    完成的

    PATINDEX(jsontagpattern, json)

  2. 下一步是找到标签右侧的JSON数据部分,因为这将以bb字段的值开头。

    RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1)

  3. 从上面返回的字符串中,找到第一个双引号,因为它表示bb的值结束的位置:

    PATINDEX( '%"%', RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1) )

  4. 使用以下内容获取JSON字段bb的值(例如,返回1234567890):

    LEFT( RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1), PATINDEX( '%"%', RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1) ) - 1 )

  5. ISNUMERIC() function应用于上述值。如果是数字则返回1,否则返回0。

  6. 如果ISNUMERIC()返回0,则返回原始JSON数据。但是,如果ISNUMERIC()返回1,则使用STUFF() function替换bb字段的值。

  7. 示例输入&输出

    给出以下输入:

    {
            "field1": "value1",
            "block1": {
                "aaa": "string",
                "bb": "1234567890"       <----- Numeric value 
            }
        }
    {
            "field1": "value2",
            "block1": {
                "aaa": "string",
                "bb": "1a23456789b0"     <----- Non-numeric value 
            }
        }
    

    返回的输出是:

    {
            "field1": "value1",
            "block1": {
                "aaa": "string",
                "bb": "XXXX"             <----- Numeric value replaced by string 
            }
        }
    {
            "field1": "value2",
            "block1": {
                "aaa": "string",
                "bb": "1a23456789b0"     <----- Non-numeric value unchanged 
            }
        }