代码之家  ›  专栏  ›  技术社区  ›  BVernon

SQL Server 2012的JSON值?

  •  1
  • BVernon  · 技术社区  · 6 年前

    我想从SQL中的JSON字符串中提取值。我开始写一个函数来完成这个任务,但是我想“肯定有人已经做过了?”。当我看到SQL Server中现在有一个JSON值函数时,我非常兴奋。。。但当我意识到它直到2016年才被添加时,我非常失望(

    1 回复  |  直到 6 年前
        1
  •  3
  •   BVernon    6 年前

    既然似乎还没有人能提供什么,下面是我到目前为止写的代码。也许它会帮助下一个站在我的立场上的人。我决定根据要检索的值的类型使用不同的函数。需要特别注意的是,date函数用于检索自1970年以来的毫秒数,decimal函数有一个参数指定是否引用该值。

    create function [dbo].[GetJsonDateValue](@Key varchar(100), @data nvarchar(max))
    returns datetime
    as
    begin
        declare @keyIdx int = charindex(@Key, @data)
        declare @valueIdx int = @keyIdx + len(@Key) + 2 -- +2 to account for characters between key and value
        declare @termIdx int = charindex(',', @data, @keyIdx)
    
        -- In case it's last item in an object
        if @termIdx = 0
        set @termIdx = charindex('}', @data, @keyIdx)
    
        declare @valueLength int = @termIdx - @valueIdx
        declare @secondsSince1970 bigint = cast(substring(@data, @valueIdx, @valueLength) as bigint) / 1000
    
        declare @retValue datetime = dateadd(s, @secondsSince1970, '19700101')
        return @retValue
    end
    GO
    
    CREATE function [dbo].[GetJsonDecimalValue](@Key varchar(100), @data nvarchar(max), @quoted bit)
    returns decimal(9,2)
    as
    begin
        declare @keyIdx int = charindex(@Key, @data)
        declare @valueIdx int = @keyIdx + len(@Key) + 2 -- +2 to account for characters between key and value
                + case when @quoted = 1 then 1 else 0 end -- +1 more for quote around value if present
        declare @termIdx int = charindex(case @quoted when 1 then '"' else ',' end, @data, @valueIdx)
    
        -- In case it's last item in an object and not quoted
        if @quoted = 0 and @termIdx = 0
        set @termIdx = charindex('}', @data, @keyIdx)
    
        declare @valueLength int = @termIdx - @valueIdx
    
        if @valueLength = 0
        return null
    
        declare @retValue decimal(9,2) = cast(substring(@data, @valueIdx, @valueLength) as decimal(9,2))
        return @retValue
    end
    GO
    
    CREATE function [dbo].[GetJsonStringValue](@Key varchar(100), @data nvarchar(max))
    returns varchar(max)
    as
    begin
        declare @keyIdx int = charindex(@Key, @data)
        declare @valueIdx int = @keyIdx + len(@Key) + 3 -- +3 to account for characters between key and value
        declare @termIdx int = charindex('"', @data, @valueIdx)
    
        declare @valueLength int = @termIdx - @valueIdx
        declare @retValue varchar(max) = substring(@data, @valueIdx, @valueLength)
        return @retValue
    end
    GO
    
        2
  •  2
  •   rumata28    4 年前

    • 返回字符串、数字或null和句柄
    • 一个更好的/健壮的查找-如果键是其他字符串值的一部分,它将按 "key": ,不仅仅是 key .
    CREATE FUNCTION [dbo].[GetJsonValue](@key varchar(100), @data nvarchar(max))
    RETURNS nvarchar(max)
    AS
    BEGIN
      DECLARE @keyJson varchar(105) = '"' + @key+ '":'
      DECLARE @keyIdx int = CHARINDEX(@keyJson, @data)
      IF @keyIdx = 0 RETURN null
    
      DECLARE @valueIdx int = @keyIdx + LEN(@keyJson)
      DECLARE @termIdx int = CHARINDEX('"', @data, @valueIdx)
    
      IF @termIdx <> 0 BEGIN
        SET @valueIdx = @valueIdx + 1
        SET @termIdx = CHARINDEX('"', @data, @valueIdx)
    
        -- Overcome JSON qoute escape
        WHILE SUBSTRING(@data, @termIdx-1, 1) = '\'
        BEGIN
          SET @termIdx = CHARINDEX('"', @data, @termIdx + 1)
        END
      END ELSE BEGIN
        SET @termIdx = CHARINDEX(',', @data, @valueIdx)
        IF @termIdx = 0 SET @termIdx = CHARINDEX('}', @data, @valueIdx)
      END
    
      IF @termIdx = 0 RETURN null
    
      -- Replace escapte quote before return value
      RETURN REPLACE(SUBSTRING(@data, @valueIdx, @termIdx - @valueIdx), '\"', '"')
    END
    

    • 不支持处理嵌套对象,而且如果键位于对象的某个深处,它可能会给出错误的结果
    • 只支持按键返回标量值

    以下是一些测试:

    -- These work just fine
    print [dbo].[GetJsonValue]('foo', '{"foo":"bar"}')
    print [dbo].[GetJsonValue]('foo', '{"foo":"Quoted \"bar\""}')
    print [dbo].[GetJsonValue]('foo', '{"foo":55}')
    print [dbo].[GetJsonValue]('foo', '{"foo":null}')
    print [dbo].[GetJsonValue]('foo', '{"a":"foo","foo":"baz"}')   -- no false positive
    
    -- CANNOT HANDLE SPACES
    print [dbo].[GetJsonValue]('foo', '{"foo":   "bar"}')
    
    -- FALSE POSITIVE!!!
    print [dbo].[GetJsonValue]('foo', '{"nested:{"foo":123}}')
    print [dbo].[GetJsonValue]('foo', '[{"foo":123}]')
    

    bar
    Quoted "bar"
    55
    null
    baz
    
    123
    123