Arrays 使用SQL Server函数将JSON数组分解为子表

Arrays 使用SQL Server函数将JSON数组分解为子表,arrays,json,sql-server,Arrays,Json,Sql Server,下面是我想使用SQL Server JSON函数将JSON分解为三个表: { "school" : "Ecole", "classes": [ { "className": "Math", "Students": ["LaPlace", "Fourier","Euler","Pascal"] } { "className": "Science"

下面是我想使用SQL Server JSON函数将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数组来提取第三个表的数据,使其看起来像这样:

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
*/
数学类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"}]
但我不确定这会让事情变得更容易。无论如何,我仍然想知道如何编写查询来完成第一个案例

类似这样:

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
*/
大概是这样的:

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
*/

从SQL Server 2016开始支持JSON

由于您的JSON嵌套更深(类数组包含学生数组),我将结合使用
OPENJSON
with
-子句来解决这个问题。请在
WITH
-子句中更靠近
AS JSON
。这将允许另一个
交叉应用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       |
+-------+--------+-----------+---------+--------------+-----------+

从SQL Server 2016开始支持JSON

由于您的JSON嵌套更深(类数组包含学生数组),我将结合使用
OPENJSON
with
-子句来解决这个问题。请在
WITH
-子句中更靠近
AS JSON
。这将允许另一个
交叉应用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       |
+-------+--------+-----------+---------+--------------+-----------+

JSON_值和openjson在哪个版本的SQL Server.SQL Server 2016+和Azure SQL数据库中工作。David,谢谢!你能推荐一个好的资源来学习更多关于SQL的知识,包括查询JSON的新功能吗?这里是“官方”中心,虽然也有大量的第三方内容。JSON_值和openjson在哪个版本的SQL Server.SQL Server 2016+和Azure SQL数据库中工作。David,谢谢!你能推荐一个好的资源来学习更多关于SQL的知识,包括查询JSON的新功能吗?这里是“官方”中心,虽然也有大量的第三方内容。这也是一个好答案,因为案例可用于设置数学和科学ID的其他值。这也是一个好答案,因为案例可用于设置数学和科学ID的其他值。