在我的表格中,我有一个包含json
:
{
"field1": "value1",
"block1": {
"aaa": "string",
"bb": "1234567890"
}
}
如何编写一个sql查询来检查bb字段的值是否为数字,如果是,请将其替换为字符串?
结果如下:
{
"field1": "value1",
"block1": {
"aaa": "string",
"bb": "xxxxxxxxxx"
}
}
请注意,json
可能包含block1之前的其他块。
我正在使用SQL server 2014
。
答案 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
解释
第一步是找到bb
标记的位置。这是由PATINDEX()
function:
PATINDEX(jsontagpattern, json)
下一步是找到标签右侧的JSON数据部分,因为这将以bb字段的值开头。
RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1)
从上面返回的字符串中,找到第一个双引号,因为它表示bb的值结束的位置:
PATINDEX(
'%"%',
RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1)
)
使用以下内容获取JSON字段bb的值(例如,返回1234567890):
LEFT(
RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1),
PATINDEX(
'%"%',
RIGHT(json, LEN(json) - PATINDEX(jsontagpattern, json) - jsontaglength + 1)
) - 1
)
将ISNUMERIC()
function应用于上述值。如果是数字则返回1,否则返回0。
如果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
}
}