数组中的嵌套对象可同时插入和更新到许多表中

时间:2018-12-13 19:28:26

标签: json sql-server tsql

我要发送的对象带有嵌套数组和数组中的对象。此过程应根据是否存在ID更新表中的数据,如果不存在,则应将其插入表中。执行此过程时,它仅更新外部对象(cases表)和包含caseIdentifierId的标识符数组中的对象。它不会在case_identifiers表中创建新的案例标识符,而应该这样做。标识符数组中的研究者和服务数组应该知道它们属于该标识符,因此已添加了“ importId”。每个标识符对象都有其自己的importId。包含“ seqId”的调查者和服务意味着它们是以前创建的,因此应在表中更新而不是插入。

ALTER PROCEDURE cases_updateAll

@caseObj NVARCHAR(MAX)

/*
DECLARE @caseObj NVARCHAR(MAX) = N'[
        {
          "caseId": 1010,
          "caseName": "Fruit",
          "identifiers": [
              {
                "caseIdentifierId": 1030,
                "importId": 2,
                "identifierName": "Apple",
                "investigators": [
                    {
                      "seqId": 50,
                      "importId": 2,
                      "investigatorId": 163,
                      "investigatorTypeCd": "LI"
                    },
                    {
                      "importId": 2,
                      "investigatorId": 178,
                      "investigatorTypeCd": "RV"
                    }
                ],
                "services": [
                    {
                      "importId": 2,
                      "serviceId": 115,
                      "serviceCatCd": "OTH",
                      "servicePrice": 2250
                    },
                    {
                      "importId": 2,
                      "serviceId": 110,
                      "serviceCatCd": "INTL",
                      "servicePrice": 900
                    }
                ]
              },
              {
                "importId": 3,
                "identifierName": "Orange",
                "investigators": [
                    {
                      "importId": 3,
                      "investigatorId": 139,
                      "investigatorTypeCd": "RV"
                    },
                    {
                      "importId": 3,
                      "investigatorId": 138,
                      "investigatorTypeCd": "SI"
                    }
                ],
                "services": [
                    {
                      "importId": 3,
                      "serviceId": 107,
                      "serviceCatCd": "DD",
                      "servicePrice": 44550
                    }
                ]
              }
          ]
        }
    ]';
 EXECUTE cases_updateAll @caseObj=@caseObj
*/

AS

DECLARE @importId INT
SET @importId = 1

BEGIN

----------更新案例表----------

WITH json_data as
(
    SELECT *
    FROM OPENJSON(@caseObj) A
    CROSS APPLY OPENJSON(A.value)
    WITH
    (
        caseId INT,
        caseName NVARCHAR(500)
    )
)

UPDATE c 
SET
    date_modified = GETUTCDATE(),
    case_name = jd.caseName, 
    import_id = @importId
FROM
    cases AS c
    INNER JOIN json_data AS jd ON jd.caseId = c.case_id

WHERE case_id = jd.caseId

----------更新并插入case_identifiers表----------

select B.*
INTO #tmpIdents
FROM OPENJSON(@caseObj)
WITH (
    identifiers NVARCHAR(MAX) AS JSON
) AS caseIdents
CROSS APPLY OPENJSON (caseIdents.identifiers)
WITH (
    caseIdentifierId INT,
    identifierName NVARCHAR(500),
    importId INT
) B;

WITH Acte AS
(
    SELECT c.*,ci.case_identifier_id AS case_ident_id
    FROM #tmpIdents c
    INNER JOIN case_identifiers ci ON c.importId=ci.import_id
)
MERGE case_identifiers AS Target
USING (SELECT * FROM Acte) AS SOURCE
ON Target.case_identifier_id = Source.caseIdentifierId
WHEN MATCHED THEN UPDATE SET
    date_modified = GETUTCDATE(),
    identifier_name = Source.identifierName,
    import_id = Source.importId
WHEN NOT MATCHED THEN
INSERT(
    identifier_name,
    import_id
)
VALUES(
    Source.identifierName,
    Source.importId
);

----------插入case_to_case_identifier ----------

INSERT INTO case_to_case_identifier
(case_id, case_identifier_id)
SELECT c.case_id, ci.case_identifier_id
FROM #tmpIdents ti
INNER JOIN cases c ON c.import_id=1
INNER JOIN case_identifiers ci ON ci.import_id=ti.importId

----------插入case_identifier_to_investigator表----------

select C.*
INTO #tmpInvs
FROM OPENJSON(@caseObj)
WITH (
    identifiers NVARCHAR(MAX) AS JSON
) AS caseIdents
CROSS APPLY OPENJSON (caseIdents.identifiers)
WITH (
    investigators NVARCHAR(MAX) AS JSON
) AS caseIdentInvs
CROSS APPLY OPENJSON (caseIdentInvs.investigators)
WITH (
    investigatorId INT,
    investigatorTypeCd CHAR(5),
    importId INT,
    seqId INT
) C;

WITH cte AS
(
    SELECT c.*,ci.case_identifier_id AS case_ident_id
    FROM #tmpInvs c
    INNER JOIN case_identifiers ci ON c.importId=ci.import_id
    INNER JOIN kdd_investigator_type ki ON c.investigatorTypeCd=ki.investigator_type_cd
)
MERGE case_identifier_to_investigator AS Target
USING (SELECT * FROM cte) AS SOURCE
ON Target.seq_id = Source.seqId
WHEN MATCHED THEN UPDATE SET
    investigator_id = Source.investigatorId,
    investigator_type_cd = Source.investigatorTypeCd
WHEN NOT MATCHED THEN
INSERT(investigator_id, case_identifier_id, investigator_type_cd)
VALUES(Source.investigatorId, Source.case_ident_id, Source.investigatorTypeCd);

---------- INSERT INTO case_identifier_to_service表----------

select D.*
INTO #tmpServs
FROM OPENJSON(@caseObj)
WITH (
    [services] NVARCHAR(MAX) AS JSON
) AS caseIdentServs
CROSS APPLY OPENJSON (caseIdentServs.[services])
WITH (
    serviceId INT,
    importId INT,
    seqId INT,
    servPrice DECIMAL
) D;

WITH Scte AS
(
    SELECT c.*,ci.case_identifier_id AS case_ident_id
    FROM #tmpServs c
    INNER JOIN case_identifiers ci ON c.importId=ci.import_id
)
MERGE case_identifier_to_service AS Target
USING (SELECT * FROM Scte) AS SOURCE
ON Target.seq_id = Source.seqId
WHEN MATCHED THEN UPDATE SET
    service_id = Source.serviceId
WHEN NOT MATCHED THEN
INSERT(service_id, case_identifier_id, service_price)
VALUES(Source.serviceId, Source.case_ident_id, Source.servPrice);

----------将importId设置为NULL ----------

UPDATE case_identifiers SET import_id = null;
UPDATE cases SET import_id = null;

END

----------表格图----------

Cases
+-------------+---------+
|  import_id  | case_id |
+-------------+---------+
| NULL        | 1008    |
| NULL        | 1009    |
| 1           | 1010    | <--- @importId sets this to 1
+-------------+---------+

TmpIdents (c)
+-------------+---------------+
|  import_id  | case_ident_id |
+-------------+---------------+
| 2           | 1030          |
| 3           | NULL          |
+-------------+---------------+

Case Identifiers (ci)
+-------------+---------------+
|  import_id  | case_ident_id |
+-------------+---------------+
| 2           | 1030          |
| 3           | NULL          | <--- will become 1040
+-------------+---------------+

Case to Case Identifiers
+-------------+--------------+---------------+--------+
|  import_id  |   case_id    | case_ident_id | seq_id |
+-------------+--------------+---------------+--------+
| 2           | 1010         | 1030          | 50     |
| 3           | 1010         | 1040          | 51     |
+-------------+--------------+---------------+--------+

Case Identifier to Investigator
+-------------+---------+--------------+---------------+--------+
|  import_id  | inv_id  | inv_type_cd  | case_ident_id | seq_id |
+-------------+---------+--------------+---------------+--------+
| 2           | 163     | LI           | 1030          | 64     |
| 2           | 178     | RV           | 1030          | 65     |
| 3           | 139     | RV           | 1040          | 66     |
| 3           | 138     | SI           | 1040          | 67     |
+-------------+---------+--------------+---------------+--------+

Case Identifier to Service
+-------------+---------+---------------+--------+
|  import_id  | serv_id | case_ident_id | seq_id |
+-------------+---------+---------------+--------+
| 2           | 115     | 1030          | 23     |
| 2           | 110     | 1030          | 24     |
| 3           | 107     | 1040          | 25     |
+-------------+---------+---------------+--------+

1 个答案:

答案 0 :(得分:0)

这个答案来得很晚,希望它还是有帮助的。

您的问题是 TL; TR ,但我想我可以为您指出一种替代方法,该方法使工作更加轻松:尝试将整批商品读取到暂存表中然后从那里继续:

DECLARE @caseObj NVARCHAR(MAX) = N'[
    {
      "caseId": 1010,
      "caseName": "Fruit",
      "identifiers": [
          {
            "caseIdentifierId": 1030,
            "importId": 2,
            "identifierName": "Apple",
            "investigators": [
                {
                  "seqId": 50,
                  "importId": 2,
                  "investigatorId": 163,
                  "investigatorTypeCd": "LI"
                },
                {
                  "importId": 2,
                  "investigatorId": 178,
                  "investigatorTypeCd": "RV"
                }
            ],
            "services": [
                {
                  "importId": 2,
                  "serviceId": 115,
                  "serviceCatCd": "OTH",
                  "servicePrice": 2250
                },
                {
                  "importId": 2,
                  "serviceId": 110,
                  "serviceCatCd": "INTL",
                  "servicePrice": 900
                }
            ]
          },
          {
            "importId": 3,
            "identifierName": "Orange",
            "investigators": [
                {
                  "importId": 3,
                  "investigatorId": 139,
                  "investigatorTypeCd": "RV"
                },
                {
                  "importId": 3,
                  "investigatorId": 138,
                  "investigatorTypeCd": "SI"
                }
            ],
            "services": [
                {
                  "importId": 3,
                  "serviceId": 107,
                  "serviceCatCd": "DD",
                  "servicePrice": 44550
                }
            ]
          }
      ]
    }
]';

-通过为任何嵌套列表添加APPLY OPENJSON,查询将越来越深入。
-将结果隐式写入物理表

SELECT A.caseId
      ,A.caseName
      ,identif.caseIdentifierId AS identif_caseIdentifier
      ,identif.importId AS identif_importId
      ,identif.identifierName AS identif_identifierName
      ,invest.seqId AS invest_seqId
      ,invest.importId AS invest_importId
      ,invest.investigatorId AS invest_investigatorId
      ,invest.investigatorTypeCd AS invest_investigatorTypeCd
      ,serv.importId AS serv_importId
      ,serv.serviceId AS serv_serviceId
      ,serv.serviceCatCd AS serv_serviceCatCd
      ,serv.servicePrice AS serv_servicePrice
INTO #tmpStagingTable
FROM OPENJSON(@caseObj)
WITH(caseId INT, caseName NVARCHAR(200)
    ,identifiers NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.identifiers)
WITH(caseIdentifierId INT, importId INT, identifierName NVARCHAR(200)
    ,investigators NVARCHAR(MAX) AS JSON
    ,[services] NVARCHAR(MAX) AS JSON) identif
OUTER APPLY OPENJSON(identif.investigators)
WITH(seqId INT, importId INT, investigatorId INT, investigatorTypeCd NVARCHAR(100)) invest
OUTER APPLY OPENJSON(identif.[services])
WITH(importId INT,serviceId INT,serviceCatCd NVARCHAR(100),servicePrice DECIMAL(10,4)) serv;

-查看结果

SELECT * FROM #tmpStagingTable;

+--------+----------+------------------------+------------------+------------------------+--------------+-----------------+-----------------------+---------------------------+---------------+----------------+-------------------+-------------------+
| caseId | caseName | identif_caseIdentifier | identif_importId | identif_identifierName | invest_seqId | invest_importId | invest_investigatorId | invest_investigatorTypeCd | serv_importId | serv_serviceId | serv_serviceCatCd | serv_servicePrice |
+--------+----------+------------------------+------------------+------------------------+--------------+-----------------+-----------------------+---------------------------+---------------+----------------+-------------------+-------------------+
| 1010   | Fruit    | 1030                   | 2                | Apple                  | 50           | 2               | 163                   | LI                        | 2             | 115            | OTH               | 2250.0000         |
+--------+----------+------------------------+------------------+------------------------+--------------+-----------------+-----------------------+---------------------------+---------------+----------------+-------------------+-------------------+
| 1010   | Fruit    | 1030                   | 2                | Apple                  | 50           | 2               | 163                   | LI                        | 2             | 110            | INTL              | 900.0000          |
+--------+----------+------------------------+------------------+------------------------+--------------+-----------------+-----------------------+---------------------------+---------------+----------------+-------------------+-------------------+
| 1010   | Fruit    | 1030                   | 2                | Apple                  | NULL         | 2               | 178                   | RV                        | 2             | 115            | OTH               | 2250.0000         |
+--------+----------+------------------------+------------------+------------------------+--------------+-----------------+-----------------------+---------------------------+---------------+----------------+-------------------+-------------------+
| 1010   | Fruit    | 1030                   | 2                | Apple                  | NULL         | 2               | 178                   | RV                        | 2             | 110            | INTL              | 900.0000          |
+--------+----------+------------------------+------------------+------------------------+--------------+-----------------+-----------------------+---------------------------+---------------+----------------+-------------------+-------------------+
| 1010   | Fruit    | NULL                   | 3                | Orange                 | NULL         | 3               | 139                   | RV                        | 3             | 107            | DD                | 44550.0000        |
+--------+----------+------------------------+------------------+------------------------+--------------+-----------------+-----------------------+---------------------------+---------------+----------------+-------------------+-------------------+
| 1010   | Fruit    | NULL                   | 3                | Orange                 | NULL         | 3               | 138                   | SI                        | 3             | 107            | DD                | 44550.0000        |
+--------+----------+------------------------+------------------+------------------------+--------------+-----------------+-----------------------+---------------------------+---------------+----------------+-------------------+-------------------+

由此您可以继续。有多种方法:

  • 通过MERGE进行选择,在您的所有表中使用多个GROUP BY语句。
  • 通过检查是否存在来使用
  • 自创建合并并插入或更新所需的任何内容。
  • 将列添加到登台表中,并使用目标中找到的ID进行更新。然后使用该ID进行操作

通过这样的操作,我建议始终在两者之间放置一个暂存步骤。