4

I'm trying to find a way to query JSON in SQL similarly to querying XML. Any ideas? I don't have any data saved yet, so I'm pretty much open, although I've read the best way to save JSON is by using a column that is varchar(max).

Thanks

Example:

Let's say the following JSON object is stored in a varchar(max) column, and I want to query the column pulling out all transaction IDs with the "success" flag = False.

{"TransactionID":"sample string 1","Success":true,
 "Response":"sample string 3","Values":"sample string 4"}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
RandomlyOnside
  • 436
  • 1
  • 9
  • 22
  • SQL Server currently has no native JSON support, so you'd have to read this column as a string into e.g. C#, then parse the JSON into objects (using a JSON library) and then do your processing. SQL Server (as of version 2005 and newer) does have native **XML** support .... – marc_s Feb 24 '15 at 15:48
  • Thanks @marc_s. So my other thought is to convert this to XML before inserting it. Is there an easy way to convert a JSON string to XML in VB (or C)? Perhaps this should be a different question altogether? – RandomlyOnside Feb 24 '15 at 15:52
  • I remember, that there was an option of writing stored procedures and/or functions in C# - it would be simple then :) – Gerino Feb 24 '15 at 15:56
  • 2
    @JoshuaHarris have you considered JSON.NET (http://json.codeplex.com/)? It can convert json to and from XML. Do it in C#, then insert the result to SQL. – Code Different Feb 24 '15 at 16:44
  • @ZoffDino - this is my current solution of choice. – RandomlyOnside Apr 27 '15 at 16:08
  • Almost dup of [Parse JSON in TSQL](/q/2867501/1178314), which asks with a parameter as a source instead of a column, but have good answers and now mention the native JSON support in SQL Server 2016. – Frédéric Feb 26 '16 at 12:35
  • Possible duplicate of [Parse JSON string in sql](http://stackoverflow.com/questions/12235504/parse-json-string-in-sql) – Frédéric Feb 26 '16 at 12:41

2 Answers2

0

Moral of the story: Don't do this using SQL. CLR and a JSON wrapper are the way to go. But if you are truly curious you could do something like below. There are so many problems that could happen it would be difficult to list them all. A quick google on the topic will easily show why. If you can ensure perfectly perfectly perfectly formed JSON objects this may be something you could look into. Maybe. Don't use this.

/*
JSON to XML Parser TSQL
Compatibility: TEsted on SQL Server 2014
Assumptions:    -Perfectly formed JSON as declared below.
                -Charecters for formatting are ok but will be removed
*/

--Imagine @JSONDATA would be the parameter to your function
DECLARE @JSONDATA VARCHAR(MAX) = '{"transactions":[
                                        {"TransacitonID":"transaction1","Success":true,"Response":"sample string 1","Values":"sample string 1"},
                                        {"TransactionID":"transaction2","Success":false,"Response":"sample string 2","Values":"sample string 2"}
                                ]}'

DECLARE @ObjectArrayNameStart INT
DECLARE @ObjectArrayNameEnd INT
DECLARE @ObjectArray VARCHAR(MAX)
DECLARE @ObjectArrayName VARCHAR(MAX)
DECLARE @ObjectArrayBracketStart INT
DECLARE @ObjectArrayBracketEnd INT
DECLARE @ObjectArraySingleton VARCHAR(MAX)
DECLARE @ObjectXML XML



--Replace All CR and LF charecters and HT chars
SET @JSONDATA = REPLACE(REPLACE(REPLACE(@JSONDATA,CHAR(10),''),CHAR(13),''),CHAR(9),'') --LF

--Get the ObjectArrayName
SELECT @ObjectArrayNameStart = PATINDEX('%{["]transactions["]:[[]%',@JSONDATA), @ObjectArrayNameEnd = PATINdEX('%[[]%',@JSONDATA)
SET @ObjectArrayName = SUBSTRING(@JSONDATA,@ObjectArrayNameStart,@ObjectArrayNameEnd)

--Get the ObjectArray name
SET @ObjectArray = REPLACE(@JSONDATA,@ObjectArrayName,'')

----Trim out the word of the object array and get the single word and singleton item
SET @ObjectArrayName = LEFT(@ObjectArrayName,@ObjectArrayNameEnd - 3)
SET @ObjectArrayName = RIGHT(@ObjectArrayName, LEN(@ObjectArrayName) - 2)
SET @ObjectArraySingleton = 'node'

--PREP THE JSON OBJECT DOWN TO INDIVIDUAL OBJECTS AND SET AS XML DOCUMENT
SET @ObjectArray = LTRIM(RTRIM(REPLACE(@ObjectArray,']}','')))
SET @ObjectArray = REPLACE(@ObjectArray,'},{','</' + @ObjectArraySingleton + '><' + @ObjectArraySingleton + '>')
SET @ObjectArray = REPLACE(@ObjectArray,'{','<' + @ObjectArraySingleton + '>')
SET @ObjectArray = REPLACE(@ObjectArray,'}','</' + @ObjectArraySingleton + '>')
SET @ObjectArray = '<root>' + @ObjectArray + '</root>'
SET @ObjectXML =  CAST(@ObjectArray AS XML)

--Query for line data
;WITH XMLObjectData AS (
    SELECT  Item.value('text()[1]','nvarchar(max)') AS ObjectLine
    FROM    @ObjectXML.nodes('/root/node') AS Items(Item)
), CommaSplit AS (
    SELECT  '<pair><key>' + REPLACE(X.ObjectLine,',','</value></pair><pair><key>') + '</value></pair>' AS ObjectLine
    FROM    XMLObjectData AS X
), ColonSplit AS (
    SELECT  REPLACE(X.ObjectLine,':','</key><value>') AS ObjectLine
    FROM    CommaSplit AS X
), QuoteReplace AS (
    SELECT  REPLACE(X.ObjectLine,'"','') AS ObjectLine
    FROM    ColonSplit AS X
)
SELECT  CAST(F.ObjectLine AS XML)
FROM    QuoteReplace AS F
FOR     XML PATH('object'), ROOT('root')


--COMMENTED OUT FOR TESTING
--SELECT    @JSONDATA AS JSONData, 
--      @ObjectArrayName AS ObjArrayName, 
--      @ObjectArrayNameStart AS ObjArrayNameStart, 
--      @ObjectArrayNameEnd AS ObjArrayNameEnd,
--      @ObjectArray AS ObjArray,
--      @ObjectArraySingleton AS ObjSingleton
--      --,CAST(@ObjectArray AS XML) AS XMLObjectArray
Matt
  • 1,441
  • 1
  • 15
  • 29
0
    select ca.TransactionID, ca.Success, ca.Response, cs.Values from 
    table_name tn with(NOLOCK)
    CROSS APPLY(select * from OPENJSON(tn.JSONColumnName) WITH(
    [TransactionID] nvarchar(50) '$.TransactionID',
    [Success] bit '$,Success',
    [Response] nvarchar(50), '$.Response',
    [Values] nvarchar(50) '$.Values'
    )) ca
    Where ca.Success = 0
Rakesh Raut
  • 183
  • 3
  • 12
  • A blob of code is not a great answer, especially if you are going to try and answer some ancient question. Give us some context and convince us this solves the problem at hand for anyone who stumbles across this. –  Feb 26 '19 at 16:32
  • I jut tried to answer the question. Even if the question is ancient, users may face this situation anytime. So it really does not matter, which way question is answered irrespective of question is old or new. – Rakesh Raut Mar 07 '19 at 17:02
  • Did you read [answer]? I'm saying that a blob of code is not a complete answer. It isn't about how old it is. If you took the time to answer and ancient question at least take the time to make it a _good_ answer. –  Mar 07 '19 at 17:38