Reputation: 11
Currently, I am using SQL Server 2016 with JSON and I want to join collections together. So far I created two collections:
CREATE TABLE collect_person(person...)
CREATE TABLE collect_address(address...)
The JSON document will look like this in the first collection (collection_person):
{
"id" : "P1",
"name" : "Sarah",
"addresses" : {
"addressId" : [
"ADD1",
"ADD2"
]
}
}
The JSON documents will look like these below in the second collection (collect_address):
{
"id" : "ADD1",
"city" : "San Jose",
"state" : "CA"
}
{
"id" : "ADD2",
"city" : "Las Vegas"
"state" : "NV"
}
I want to get the addresses of the person named "Sarah", so the output will be something like:
{
{"city" : "San Jose", "state" : "CA"},
{"city" : "Las Vegas", "state" : "NV"}
}
I do not want to convert JSON to SQL and SQL to JSON. Is this possible to do in SQL Server 2016 with JSON and please show me how? Thank you in advance.
Upvotes: 0
Views: 818
Reputation: 834
I am a little late to the question, but it can be done via cross apply and I also used common table expressions. Depending on the table size I would suggest creating a persisted computed column on the id fields for each table assuming that the data won't change and that there was a single addressId per record or add some other key value that can be indexed on and used to limit the records that need to be converted to JSON. This is a simple example and it hasn't been tested for performance so "YMMV".
Building Example Tables
DECLARE @collect_person AS TABLE
(Person NVARCHAR(MAX))
DECLARE @collect_address as TABLE
([Address] NVARCHAR(MAX))
INSERT INTO @collect_person (Person)
SELECT N'{
"id" : "P1",
"name" : "Sarah",
"addresses" : {
"addressId" : [
"ADD1",
"ADD2"
]
}
}'
INSERT INTO @collect_address ([Address])
VALUES
(N'{
"id" : "ADD1",
"city" : "San Jose",
"state" : "CA"
}')
,('{
"id" : "ADD2",
"city" : "Las Vegas",
"state" : "NV"
}')
Querying the Tables
;WITH persons AS (
SELECT --JP.*
JP.id
,JP.name
,JPA.addressId -- Or remove the with clause for JPA and just use JPA.value as addressId
FROM @collect_person
CROSS APPLY OPENJSON([person])
WITH (
id varchar(50) '$.id'
,[name] varchar(50) '$.name'
,addresses nvarchar(max) AS JSON
) as JP
CROSS APPLY OPENJSON(JP.addresses, '$.addressId')
WITH (
addressId varchar(250) '$'
) AS JPA
)
,Addresses AS (
SELECT A.*
FROM @collect_address AS CA
CROSS APPLY OPENJSON([Address])
WITH (
id varchar(50) '$.id'
,city varchar(50) '$.city'
,state varchar(2) '$.state'
) as A
)
SELECT * FROM persons
INNER JOIN Addresses
ON persons.addressId = Addresses.id
Again this is not the ideal way to do this, but it will work and as stated before you should probably have a key field on each table that is indexed to limit the scans and JSON Parsing done on the table.
There is native compilation, but it is new to me and I am not familiar with the pros and cons.
Optimize JSON processing with in-memory OLTP
Upvotes: 1