使用SQL Server函数将JSON数组切入子表

时间:2019-02-13 01:09:05

标签: arrays json sql-server

这里是JSON,我想使用SQL Server JSON函数切成三个表:

   { 
        "school" : "Ecole",
        "classes": [
         {
          "className": "Math",
          "Students": ["LaPlace", "Fourier","Euler","Pascal"]
         }
         {
          "className": "Science",
          "Students": ["Newton", "Einstein","Al-Biruni", "Cai"]
         },
        ]
    }

    Table 1
    +-------+--------+  
    | ID    | school |
    +-------+--------+

    Table 2
    +-------+---------------+-----------+  
    | ID    | schoolID (FK) | className |
    +-------+---------------+-----------+  

    Table 3
    +-------+---------------+-----------+  
    | ID    | classID (FK)  | student   | 
    +-------+---------------+-----------+  

到目前为止,我的查询是

SELECT * FROM OPENJSON(@json, '$.school') --Returns the name of the school

SELECT
   ClassName = JSON_VALUE(c.value, '$.className'), 
   Students = JSON_QUERY(c.value, '$.Students') 
FROM
   OPENJSON(@json, '$.classes') c

-返回班级名称和一个JSON学生数组。

我想知道如何使用SQL分解JSON数组以提取第三张表的数据,使其看起来像这样:

数学类别ID = 1 科学课ID = 2

   Id     ClassId   Student
 +-------+--------+-----------+  
 | 1     | 1      | LaPlace   | 
 +-------+--------+-----------+  
 | 2     | 1      | Fourier   | 
 +-------+--------+-----------+  
 | 3     | 1      | Euler     | 
 +-------+--------+-----------+  
 | 4     | 1      | Pascal    | 
 +-------+--------+-----------+  
 | 5     | 2      | Newton    | 
 +-------+--------+-----------+  
 | 6     | 2      | Einstein  | 
 +-------+--------+-----------+  
 | 7     | 2      | Al-Biruni |  
 +-------+--------+-----------+  
 | 8     | 2      | Cai       | 
 +-------+--------+-----------+  

我可以从其他表中获取ID,但是我不知道如何编写查询以从JSON数组中提取学生。

我确实具有重组JSON模式的能力,因此我可以创建对象数组,而不是字符串数组:

"Students": [{"StudentName"}:"Newton", {"StudentName":"Einstein"},{"StudentName":"Al-Biruni"}, {"StudentName":"Cai"}]

但是我不确定这会变得更容易。无论哪种方式,我仍然想知道如何编写查询以完成第一种情况。

2 个答案:

答案 0 :(得分:2)

从SQL Server 2016开始支持

JSON

由于您的JSON更深层嵌套(类数组包含一个学生数组),我将结合OPENJSONWITH子句来解决此问题。请稍微靠近AS JSON子句中的WITH。这将允许另一个CROSS APPLY OPENJSON(),因此将越来越深入到您的JSON结构中。

DECLARE @json NVARCHAR(MAX) = 
N'{ 
    "school" : "Ecole",
    "classes": [
     {
      "className": "Math",
      "Students": ["LaPlace", "Fourier","Euler","Pascal"]
     },
     {
      "className": "Science",
      "Students": ["Newton", "Einstein","Al-Biruni", "Cai"]
     }
    ]
}';

-查询

SELECT ROW_NUMBER() OVER(ORDER BY B.className,C.[key]) AS RowId
      ,A.school
      ,B.className
      ,CASE B.className WHEN 'Math' THEN 1 WHEN 'Science' THEN 2 ELSE 0 END AS ClassId
      ,C.[key] AS StudentIndex
      ,C.[value] AS Student    
FROM OPENJSON(@json)
WITH(school NVARCHAR(MAX)
    ,classes NVARCHAR(MAX) AS JSON) A
CROSS APPLY OPENJSON(A.classes)
WITH(className NVARCHAR(MAX)
    ,Students NVARCHAR(MAX) AS JSON) B
CROSS APPLY OPENJSON(B.Students) C

结果

+-------+--------+-----------+---------+--------------+-----------+
| RowId | school | className | ClassId | StudentIndex | Student   |
+-------+--------+-----------+---------+--------------+-----------+
| 1     | Ecole  | Math      | 1       | 0            | LaPlace   |
+-------+--------+-----------+---------+--------------+-----------+
| 2     | Ecole  | Math      | 1       | 1            | Fourier   |
+-------+--------+-----------+---------+--------------+-----------+
| 3     | Ecole  | Math      | 1       | 2            | Euler     |
+-------+--------+-----------+---------+--------------+-----------+
| 4     | Ecole  | Math      | 1       | 3            | Pascal    |
+-------+--------+-----------+---------+--------------+-----------+
| 5     | Ecole  | Science   | 2       | 0            | Newton    |
+-------+--------+-----------+---------+--------------+-----------+
| 6     | Ecole  | Science   | 2       | 1            | Einstein  |
+-------+--------+-----------+---------+--------------+-----------+
| 7     | Ecole  | Science   | 2       | 2            | Al-Biruni |
+-------+--------+-----------+---------+--------------+-----------+
| 8     | Ecole  | Science   | 2       | 3            | Cai       |
+-------+--------+-----------+---------+--------------+-----------+

答案 1 :(得分:1)

类似这样的东西:

declare @json nvarchar(max) = N'
  { 
        "school" : "Ecole",
        "classes": [
         {
          "className": "Math",
          "Students": ["LaPlace", "Fourier","Euler","Pascal"]
         },
         {
          "className": "Science",
          "Students": ["Newton", "Einstein","Al-Biruni", "Cai"]
         }
        ]
    }
';


with q as
(
SELECT
   ClassID = c.[key]+1,
   ClassName = JSON_VALUE(c.value, '$.className'), 
   Id = row_number() over (order by c.[Key], students.[key] ),
   Student = students.value
FROM
   OPENJSON(@json, '$.classes') c
cross apply openjson(c.value,'$.Students') students
)
select Id, ClassId, Student
from q


/*
Id          ClassId     Student
----------- ----------- -----------
1                    1           LaPlace
2                    1           Fourier
3                    1           Euler
4                    1           Pascal
5                    2           Newton
6                    2           Einstein
7                    2           Al-Biruni
8                    2           Cai
*/