?
Solved

MS SQL json query/where clause nested array items

Posted on 2016-11-17
2
Medium Priority
?
241 Views
Last Modified: 2017-01-05
I have json data that i can query on using "CROSS APPLY OPENJSON(" which gets slow once you start adding multiple cross applies or once your json document get too large. So i wanted to add an index on the data im trying to filter on, but i cant get the syntax on nested array items to work with out using a cross apply. As such i cant create an index as you cant use a cross apply when making an index. According to the MS docs i should just be able to do

 JSON_query(my_column, $.parentItem.nestedItemsArray1.nestedItemsArray2)

Open in new window

 

I should be able to get all the values of the nested, array items to then query on and improve performance by adding an index, something like this

  ALTER TABLE mytable 
    ADD vdata AS JSON_query(my_column, 
      $.parentItem.nestedItemsArray1.nestedItemsArray2')  
      
    CREATE INDEX idx_json_my_column ON mytable(vdata)

Open in new window

 

but the above  $.array.arrayitems syntax doesn't work ?
On a side note, I cant help but think in relational terms where normally in Sql you would index a column of data like so

 col
    ---
     1| 
     2|
     3|

Open in new window


 But json data seem to get flattened so when i use JSON_QUERY as per MS example i get "1,2,3" " I assume i want to incdex an array of values rather than a flattened version unless the index will return the inner data of the fattened data ?

my plug and play working example

  declare  @mydata table (    
      ID int NOT NULL,  
      jsondata varchar(max) NOT NULL  
    )
    
    INSERT INTO @mydata (id, jsondata)
    	VALUES (789, '{ "Id": "12345", "FinanceProductResults": [ { "Term": 12, "AnnualMileage": 5000, "Deposits": 0, "ProductResults": [] }, { "Term": 18, "AnnualMileage": 30000, "Deposits": 15000, "ProductResults": [] }, { "Term": 24, "AnnualMileage": 5000, "Deposits": 0, "ProductResults": [ { "Key": "HP", "Payment": 460.28 } ] }, { "Term": 24, "AnnualMileage": 10000, "Deposits": 0, "ProductResults": [ { "Key": "HP", "Payment": 500.32 } ] }]}')
    
    SELECT 
    	j_Id
    	,JSON_query (c.value, '$.Term') as Term
    	,JSON_Value (c.value, '$.AnnualMileage') as AnnualMileage
    	,JSON_Value (c.value, '$.Deposits') as Deposits 	
    	,JSON_Value (p.value, '$.Key') as [Key]
    	,JSON_Value (p.value, '$.Payment') as Payment
    	--,c.value
    FROM @mydata  f 
    	CROSS APPLY OPENJSON(f.jsondata)
    		WITH (j_Id nvarchar(100) '$.Id')
    	CROSS APPLY OPENJSON(f.jsondata, '$.FinanceProductResults') AS c
    	CROSS APPLY OPENJSON(c.value, '$."ProductResults"') AS p
    where 
    	ID = 789 
    	AND JSON_Value (p.value, '$.Payment') = '460.28'

Open in new window


Im using these MS docs to guide me :

How to create an index
How to get data

Update

I was able to improve performance slightly using the "with" method

    
SELECT 
    	j_Id,
		FinanceDetails.Term,
		FinanceDetails.AnnualMileage,
		FinanceDetails.Deposits,
		Payments.Payment
    FROM @mydata  f 
    	CROSS APPLY OPENJSON(f.jsondata)
    		WITH (j_Id nvarchar(100) '$.Id')
		OUTER APPLY OPENJSON (f.jsondata, '$.FinanceProductResults' )  
				WITH (   
					Term			INT				'$.Term',  
					AnnualMileage	INT				'$.AnnualMileage',  
					Deposits		INT				'$.Deposits',  
					ProductResults  NVARCHAR(MAX)	'$.ProductResults'  AS JSON  
				) AS FinanceDetails
			OUTER APPLY OPENJSON(ProductResults,  '$') 
				WITH (   
					Payment DECIMAL(19, 4)			'$.Payment' 
				) AS Payments
	WHERE	
		Payments.Payment = 460.28

Open in new window


but i still like to add an index on the sub array data to aid in improving performance ?
0
Comment
Question by:Rawdon Hume
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
2 Comments
 
LVL 2

Accepted Solution

by:
Rawdon Hume earned 0 total points
ID: 41903747
So it seems currently, you cannot index nested properties. so ill use Full-text search. I have to create FTS on JSON column and add predicate:

WHERE ....
AND CONTAINS( jsondata, 'NEAR(('Payments,460),1)')

Open in new window


Since JSON is text, this predicate will filter out all records that don't have something like "Payment" and 460 near to each other (this will identify key:value pairs), I can apply CROSS APPLY on the reduced set of rows.
0
 
LVL 2

Author Closing Comment

by:Rawdon Hume
ID: 41903748
why doesn't ms sql 2026 have better support json
0

Featured Post

Simplifying Server Workload Migrations

This use case outlines the migration challenges that organizations face and how the Acronis AnyData Engine supports physical-to-physical (P2P), physical-to-virtual (P2V), virtual to physical (V2P), and cross-virtual (V2V) migration scenarios to address these challenges.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Ever needed a SQL 2008 Database replicated/mirrored/log shipped on another server but you can't take the downtime inflicted by initial snapshot or disconnect while T-logs are restored or mirror applied? You can use SQL Server Initialize from Backup…
Recently we ran in to an issue while running some SQL jobs where we were trying to process the cubes.  We got an error saying failure stating 'NT SERVICE\SQLSERVERAGENT does not have access to Analysis Services. So this is a way to automate that wit…
Using examples as well as descriptions, and references to Books Online, show the documentation available for date manipulation functions and by using a select few of these functions, show how date based data can be manipulated with these functions.
Via a live example, show how to set up a backup for SQL Server using a Maintenance Plan and how to schedule the job into SQL Server Agent.
Suggested Courses

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question