2017-03-22 35 views
2

在我的桌子我有一個包含列的jsonSQL:檢查是否有子是數字和更換

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

如何寫一個SQL查詢來檢查,如果BB字段的值是數字,如果是,請用字符串替換它?

結果會是這樣:

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

請注意,json可以在塊1之前包含其他塊。我正在使用SQL server 2014

+0

你有一個SQL只提取和回「bb」字段的值?如果是,則使用T-SQL的['ISNUMERIC'](https://msdn.microsoft.com/en-us/library/ms186272.aspx)函數檢查它是否可以解釋爲數字,然後使用T-SQL的[字符串函數](https://msdn.microsoft.com/en-us/library/ms181984.aspx)來執行替換(即在值和連接之前/之後剪切左右部分中的字符串他們一起回來)。 – Phylyp

+0

不,我沒有查詢提取此值 –

+1

[本文](https://www.simple-talk.com/sql/t-sql-programming/consuming-json-strings-in-sql-服務器/)可能會有用。將它轉換爲表後,可以執行檢查。 – NEER

回答

0

以下查詢非常冗長,因爲它包含用於演示查詢工作的外部select語句中的各個字段。要獲得正在運行的查詢,select語句只需要最右邊的列(即CASE ... END語句)。

目的

寫來檢查,如果將BB區域的值是數字,如果是,用一個字符串替換它的SQL查詢。

下面的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字段的值。

採樣輸入&輸出

鑑於以下輸入:

{ 
     "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 
     } 
    } 
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 

如果測試看行,只需在您的表具有相同WHERE條款(WHERE ISNUMERIC(dbo.fn_getBB(@str)) = 1

希望它可以幫助運行UPDATE

PS - 該函數假定您的JSON中始終存在「bb」。如果情況並非如此,您可以隨時以WHERE條款作爲條件提供。

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