This article helps to explain the application of JSON data and the use of new SQL 2016 constructs that enable an integration of JSON data into a relational schema.
The idea behind this article is to list as many examples of JSON nested elements, an inclusion of sample data, relational data conversion to JSON data, JSON to the relational data, conversion of JSON elements into separate columns and representing the same data into separate rows.
↑ Return to Top
The JSON stands for JavaScript Object Notation. JSON is the primary data representation for all NoSQL databases. This is a natural fit for the developers, who use JSON as the data interchange format in their Applications. The relative ability of JSON (JSON records are well structured but easily extended) on its scalability has attracted the developers looking DB migrations in agile environments. Data and schema, in volume, can be hard to change. Rewriting a large dataset stored on the disk while keeping the associated Applications online can be time-consuming. It can take days of background processing, in moderate to large examples, to upgrade the data
Having these additional JSON features built into SQL Server should make it easier for the Applications to exchange JSON data with SQL Server.This functionality provides the flexibility in the integration of JSON data into the relational database engine. The developers can write and invent complex queries during their periodic stages of the development process.
Relational databases refer to the traditional data storage, Constructive and Intuitive SQL language, Complex query design and ACID property. NoSQL offers different concepts - complex structures are placed together into the collections of the entities, where you can take everything, which you need with one read operation or where you can insert complex structure with a single write and follows CAP property.
The relational databases normalize the data to some degree; that is, rather than repeating a piece of data in multiple rows, a table that needs that information will store a foreign key, which points to another table that holds the data. On the other hand, this process means that the data is typically shredded from its original form to fit into tables and then reassemble at the run time by joining the tables in response to a query. This becomes particularly expensive as the data set grows and the data need to be partitioned among the multiple database servers.
In the traditional database, normalization process ensures to minimize the amount of information that duplicates but whereas in NoSQL, intentionally duplicate it to make it easier to use. Let's say, representing a number of students taking a class. A normalized way of representing the data is given below. The use of an array denotes the dimension data of the relational table
{
course "Basic programming",
room "1A",
students[{
id 1,
name "Prashanth"
}, {
id 2,
name "Jayaram"
}]
}
Here's a denormalized data.
[{
studentId 1,
studentName "Prashanth"
studentId 2,
studentName "Jayaram"
Let's discuss the different dimensions of the sample data given below and represent the data in tabular and JSON file format. Also, you will learn to know how to query JSON file with the various available JSON constructs in SQL 2016
Native JSON support in SQL Server 2016 provides you few functions to read and parse your JSON string into a relational format.
The FOR JSON PATH clause is similar to the FOR XML PATH clause. It gives more control to define the structure using column alias with dot separator
For example,
Lets create a sample table 'EMP' and 'DEPT' and insert few rows in it
CREATE TABLE EMP
(EMPNO NUMERIC(4) NOT NULL,
ENAME VARCHAR(10),
JOB VARCHAR(9),
MGR NUMERIC(4),
HIREDATE DATETIME,
SAL NUMERIC(7, 2),
COMM NUMERIC(7, 2),
DEPTNO NUMERIC(2))
(7782, 'CLARK',
'MANAGER', 7839, '9-JUN-1981',
2450, NULL,
10)
INSERT INTO EMP VALUES
(7788, 'SCOTT',
'ANALYST', 7566, '09-DEC-1982', 3000, NULL, 20)
(7839, 'KING',
'PRESIDENT', NULL,
'17-NOV-1981',
5000, NULL,
(7844, 'TURNER',
'SALESMAN', 7698, '8-SEP-1981',
1500, 0, 30)
(7934, 'MILLER', 'CLERK', 7782, '23-JAN-1982', 1300, NULL, 10)
CREATE TABLE DEPT
(DEPTNO NUMERIC(2),
DNAME VARCHAR(14),
LOC VARCHAR(13) )
INSERT INTO DEPT VALUES (10, 'ACCOUNTING',
'NEW YORK')
INSERT INTO DEPT VALUES (20, 'RESEARCH',
'DALLAS')
INSERT INTO DEPT VALUES (30, 'SALES',
'CHICAGO')
INSERT INTO DEPT VALUES (40, 'OPERATIONS',
'BOSTON')
The output of "FOR JSON AUTO" option is given below
SELECT
* FROM
EMP E INNER
JOIN
DEPT D
ON
E.DEPTNO=D.DEPTNO
WHERE
D.DEPTNO=10
FOR
JSON AUTO
"FOR JSON PATH" option, the dot syntax is used for nested output.
E.EMPNO,E.ENAME,D.DEPTNO AS
"DEPARTMENT.DEPTNO"
,D.DNAME AS
"DEPARTMENT.DNAME",D.LOC AS
"DEPARTMENT.LOCATION"
FROM
JSON PATH
JSON PATH,ROOT('EMPLOYEE')
As we can see with PATH option creates wrapper class 'department' and nest properties deptno,dname,location
Transform the below sample data to JSON
The below transformation holds nested objects as we can see there are few more entries are added for the id 0002. In the above sample data, we can see there is four batter types and 7 toppings to prepare 28(1*4*7=28)different types of cake.similarly. for id 0002, 4 batter types and 3 toppings used to prepare 12(1*4*3) types of cake.
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters": {
"batter": [{
"id1": "1001",
"type1": "Regular"
"id1": "1002",
"type1": "Chocolate"
"id1": "1003",
"type1": "Blueberry"
"id1": "1004",
"type1": "Devils Food"
},
"topping": [{
"id2": "5001",
"type2": "None"
"id2": "5002",
"type2": "Glazed"
"id2": "5005",
"type2": "Sugar"
"id2": "5007",
"type2": "Powdered Sugar"
"id2": "5006",
"type2": "Chocolate with Sprinkles"
"id2": "5003",
"type2": "Chocolate"
"id2": "5004",
"type2": "Maple"
"id": "0002",
"name": "cup Cake",
"ppu": 0.5,
"type1": "Devil's Food"
In the following example is shown SQL code, which reads the content of the JSON file, using OPENROWSET BULK function and passes the content of JSON file (BulkColumn) to OPENJSON function
JSON file can be stored in local file system or global (Cloud storage).
ID, type, name, ppu, type1 batter, type2 topping FROM
OPENROWSET(BULK N '\\hq6021\c$\stocks.json', SINGLE_CLOB) AS
json
CROSS
APPLY OPENJSON(BulkColumn)
WITH(id nvarchar(40), type nvarchar(40), name
NVARCHAR(MAX), ppu NVARCHAR(MAX), batters NVARCHAR(MAX) AS
JSON, topping NVARCHAR(MAX) AS
JSON) AS
t
APPLY
OPENJSON(batters, '$.batter')
WITH(id1 nvarchar(100), type1 nvarchar(20))
OPENJSON(topping)
WITH(id2 nvarchar(100), type2 nvarchar(20))
Source : https//blogs.technet.microsoft.com/dataplatforminsider/2016/01/06/json-in-sql-server-2016-part-2-of-4
The dollar sign ($) represents the input JSON object (similar to root “/” in XPath language). You can add any JavaScript-like property or an array after “$” to reference properties in JSON object. One simple example of a query, where these built-in functions are used is given below.
DECLARE
@MyJSON NVARCHAR(4000) = N '{
"info" {
"type"
1, "address" {
"town"
"Louisville", "county"
"Boulder", "country"
"USA"
}, "tags" ["Snow", "Breweries"]
}, "LocationType"
"East", "WeatherType"
"Cold"
'
Select
* from
OPENJSON(@MyJSON)
WITH(type int
'$.info.type', LocationType varchar(20)
'$.LocationType', WeatherType varchar(20)
'$.WeatherType', town varchar(200)
'$.info.address.town', county varchar(200)
'$.info.address.county', country varchar(200)
'$.info.address.country') AS
OPENJSON(@MyJSON, '$.info.tags')
The examples are given above also contains a sample data that represents nested object.
DECLARE @json NVARCHAR(1000)
SELECT @json = N '{
"Employee"
"Element"
1
2
"n"
"EmployeeDepartment": [{
"EmployeeID": "E0001",
"FirstName": "Prashanth",
"LastName": "Jayaram",
"DOB": "1983-02-03",
"DEPT": [{
"EmployeeDepartment": "Ducks"
"EmployeeDepartment": "Blues"
"EmployeeID": "E0002",
"FirstName": "Prarthana",
"LastName": "Prashanth",
"DOB": "2015-07-06",
"EmployeeDepartment": "Red Wings"
"EmployeeID": "E0003",
"FirstName": "Pravitha",
"EmployeeDepartment": "Green Bird"
--SELECT * FROM OPENJSON(@MyJSON)
EmployeeID,
FirstName,
LastName,
DOB,
DEPT,
EmployeeDepartment
OPENJSON(@MyJSON, '$.EmployeeDepartment')
WITH(EmployeeID varchar(10), FirstName varchar(25), LastName varchar(25), DOB varchar(25), DEPT NVARCHAR(MAX) AS
E
OPENJSON(DEPT)
WITH(EmployeeDepartment nvarchar(100))
"DeptID": "D1",
"DName": "Ducks"
"DeptID": "D2",
"DName": "Blues"
"DeptID": "D3",
"DName": "Red Wings"
"DeptID": "D4",
"DName": "Green Bird"
JSON_Value(c.value, '$.EmployeeID') as
JSON_Value(c.value, '$.FirstName') as
JSON_Value(C.value, '$.DOB')
as
JSON_Value(p.value, '$.DeptID')
DEPTID,
JSON_Value(p.value, '$.DName')
DName
OPENJSON(@MyJSON, '$.EmployeeDepartment') as
c
APPLY OPENJSON(c.value, '$.DEPT') as
p
Dept1, DName1,
Dept2, DName2
WITH(EmployeeID varchar(20)
'$.EmployeeID', FirstName varchar(20)
'$.FirstName', DOB varchar(20)
'$.DOB', Dept1 varchar(20)
'$.DEPT[0].DeptID', Dname1 varchar(20)
'$.DEPT[0].DName', Dept2 varchar(20)
'$.DEPT[1].DeptID', Dname2 varchar(20)
'$.DEPT[1].DName') AS
EMP
SQL 2016 contains some very powerful JSON constructs. Mixing the power of the relational databases with the flexibility of JSON offers many benefits from the point of Migration, Integration, and Deployment. It is flexible because of simple syntax and lesser overhead to maintain and manage the JSON data.The powerful JSON SQL constructs enable to query and analyze JSON data as well as transform JSON to the relational data and the relational data to JSON.
There are plenty of examples and resources, which are available under various links. This is an effort to combine real-world scenarios and details the various ways of JSON data manipulation, using SQL 2016 JSON constructs. NoSQL offers different concepts - complex structures are placed together into the collections of the entities, where you can take everything, which you need with one read operation or where you can insert complex structure with a single write. The bad side is that sometimes you want to organize your information in different collections and then you will find that it is very hard to JOIN entities from the two collections.
With new SQL server, you have options to choose between these two concepts and use the best of both worlds. In your data models, you can choose when to use traditional relational structures and when to introduce NoSQL concepts.