我有一个过程应为OPENJSON并同时插入两个表中,JSON数组中的每个对象一行。例如,数组中的这两个对象会将两行数据插入“ case_idents”表中,并输出2个case_ident_id(101和102),并将这两个id插入“ case_to_case_idents”表中。此过程不会执行此操作,而是只会将case_ident_id(102)两次插入到“ case_to_case_idents”表中,从而创建一个副本而不是创建唯一的行对象。
CREATE PROCEDURE case_idents_addAll
@case_ident_id INT OUTPUT,
@seq_id INT OUTPUT,
@identObj NVARCHAR(MAX),
/*
DECLARE @case_ident_id INT
DECLARE @seq_id INT
DECLARE @identObj NVARCHAR(MAX) = N'[
{
"name": "Jack",
"entityTypeCd": "SM",
"identStatus": "PR",
"caseId": 10034,
"caseStatusCd": "NUA"
},
{
"name": "Jill",
"entityTypeCd": "SF",
"identStatus": "PR",
"caseId": 10035,
"caseStatusCd": "NA"
}
]';
EXECUTE case_idents_addAll @identObj=@identObj, @case_ident_id=@case_ident_id OUTPUT, @seq_id=@seq_id OUTPUT
*/
AS
BEGIN
INSERT INTO case_idents
(name, entity_type_cd, ident_status, case_id)
SELECT name, entity_type_cd, ident_status, case_id
FROM OPENJSON(@identObj)
WITH (
name NVARCHAR(50) '$.name',
entity_type_cd CHAR(5) '$.entityTypeCd',
ident_status CHAR(5) '$.identStatus',
case_id INT '$.caseId'
)
SET @case_ident_id=SCOPE_IDENTITY();
INSERT INTO case_to_case_ident
(case_id, case_ident_id, case_status_cd, case_ident_status_cd)
SELECT case_id, @case_ident_id, case_status_cd, case_ident_status_cd
FROM OPENJSON(@identObj)
WITH (
case_id INT '$.caseId',
case_status_cd CHAR(5) '$.caseStatusCd',
case_ident_status_cd CHAR(5) '$.identStatus'
)
SET @seq_id = SCOPE_IDENTITY();
END
答案 0 :(得分:1)
最好用中间的登台表解决这种问题:
首先,我按原样将您的JSON数据读入临时表中。此时,在将卷输入到目标表之前,您可以执行任何类型的验证和清理操作。
DECLARE @identObj NVARCHAR(MAX) =
N'[
{
"name": "Jack",
"entityTypeCd": "SM",
"identStatus": "PR",
"caseId": 10034,
"caseStatusCd": "NUA"
},
{
"name": "Jill",
"entityTypeCd": "SF",
"identStatus": "PR",
"caseId": 10035,
"caseStatusCd": "NA"
}
]';
SELECT B.*
INTO #tmpCases
FROM OPENJSON(@identObj) A
CROSS APPLY OPENJSON(A.value)
WITH
(
[name] VARCHAR(100)
,entityTypeCd VARCHAR(100)
,identStatus VARCHAR(100)
,caseId INT
,caseStatusCd VARCHAR(100)
) B;
-目标表的模型
CREATE TABLE #case_idents(ID INT IDENTITY, [name] VARCHAR(100),entity_type_cd VARCHAR(100),ident_status VARCHAR(100),case_id INT);
CREATE TABLE #case_to_case_ident(case_id INT, case_ident_id INT /*fk to other table*/,case_status_cd VARCHAR(100),case_ident_status_cd VARCHAR(100));
-插入第一个
INSERT INTO #case_idents([name],entity_type_cd,ident_status,case_id)
SELECT [name],entityTypeCd,identStatus,caseId
FROM #tmpCases;
-插入第二个
WITH cte AS
(
SELECT c.*,ci.ID AS case_ident_id
FROM #tmpCases c
INNER JOIN #case_idents ci ON c.caseId=ci.case_id
)
INSERT INTO #case_to_case_ident(case_id,case_ident_id,case_status_cd,case_ident_status_cd)
SELECT caseId,case_ident_id,caseStatusCd,identStatus
FROM cte;
-检查结果
SELECT * FROM #case_idents
SELECT * FROM #case_to_case_ident;
GO
-干净(小心真实的数据!)
DROP TABLE #tmpCases;
DROP TABLE #case_idents;
DROP TABLE #case_to_case_ident;
答案 1 :(得分:1)
您使用SCOPE_IDENTITY()的方式就是为什么在第二次插入时两个记录都具有相同的值。
SCOPE_IDENTITY()-返回插入到 同一范围内的标识列。范围是一个模块:一个存储 过程,触发器,函数或批处理。因此,如果有两个陈述 在同一个存储过程,函数或批处理中,它们在 范围相同。
SCOPE_IDENTITY()将仅返回最后一个标识值。
如果@identObj数据中具有唯一标识符,则可以使用OUTPUT clause并在插入数据时将所有标识列值捕获到表变量中,然后在第二次插入时将其联接
我问了这个问题,但是我假设您也可以探索此选项,因为case_id在@identObj中是唯一的。
--temp tables
CREATE TABLE [#case_idents]
(
[ID] INT IDENTITY
, [name] VARCHAR(255)
, [entity_type_cd] VARCHAR(255)
, [ident_status] VARCHAR(255)
, [case_id] INT
);
CREATE TABLE [#case_to_case_ident]
(
[case_id] INT
, [case_ident_id] INT
, [case_status_cd] VARCHAR(255)
, [case_ident_status_cd] VARCHAR(255)
);
--We'll use a table variable to capture all the identity field values at time of insert.
DECLARE @OutPut TABLE
(
[ID] INT
, [case_id] INT
);
DECLARE @identObj NVARCHAR(MAX) = N'[
{
"name": "Jack",
"entityTypeCd": "SM",
"identStatus": "PR",
"caseId": 10034,
"caseStatusCd": "NUA"
},
{
"name": "Jill",
"entityTypeCd": "SF",
"identStatus": "PR",
"caseId": 10035,
"caseStatusCd": "NA"
}
]';
INSERT INTO [#case_idents] (
[name]
, [entity_type_cd]
, [ident_status]
, [case_id]
)
--capture all the identities at time of insert into our table variable along with what the case_id was.
--Add OUTPUT right after your insert into the table variable. Will capture the inserted values, the identity values you're after and what case_id they are associated with
OUTPUT [Inserted].[ID]
, [Inserted].[case_id]
INTO @OutPut
SELECT [name]
, [entity_type_cd]
, [ident_status]
, [case_id]
FROM
OPENJSON(@identObj)
WITH (
[name] NVARCHAR(50) '$.name'
, [entity_type_cd] CHAR(5) '$.entityTypeCd'
, [ident_status] CHAR(5) '$.identStatus'
, [case_id] INT '$.caseId'
);
INSERT INTO [#case_to_case_ident] (
[case_id]
, [case_ident_id]
, [case_status_cd]
, [case_ident_status_cd]
)
SELECT [ident].[case_id]
, [op].[ID]
, [ident].[case_status_cd]
, [ident].[case_ident_status_cd]
FROM
OPENJSON(@identObj)
WITH (
[case_id] INT '$.caseId'
, [case_status_cd] CHAR(5) '$.caseStatusCd'
, [case_ident_status_cd] CHAR(5) '$.identStatus'
) AS [ident]
INNER JOIN @OutPut [op]
ON [op].[case_id] = [ident].[case_id]; --join here on case_id to get the identity value that was just created before that we captured and stored in our table variable.
SELECT *
FROM [#case_idents];
SELECT *
FROM [#case_to_case_ident];
答案 2 :(得分:0)
谢谢@Shnugo和@Tim,将其放入一个临时表中可以正常工作,但是我不得不更改过程的“插入第二张表”部分,因为行被重复且ident对象可以具有相同的caseId,因此,存在通过使用caseId将case_ident表连接到#tmpCase表的问题,这对于case_to_case_ident表不是唯一的。将相同的importId列添加到case_ident表和#tmpCases表中,解决了caseId不唯一的问题,并且不复制case_to_case_ident表中的行。
DECLARE @identObj NVARCHAR(MAX) =
N'[
{
"name": "Jack",
"entityTypeCd": "SM",
"identStatus": "PR",
"caseId": 10034,
"caseStatusCd": "NUA",
"importId": 100
},
{
"name": "Jill",
"entityTypeCd": "SF",
"identStatus": "PR",
"caseId": 10035,
"caseStatusCd": "NA",
"importId": 101
}
]';
SELECT B.*
INTO #tmpCases
FROM OPENJSON(@identObj) A
CROSS APPLY OPENJSON(A.value)
WITH
(
[name] NVARCHAR(50),
entityTypeCd CHAR(5),
identStatus CHAR(5),
caseId INT,
caseStatusCd CHAR(5),
importId INT
) B;
INSERT INTO case_idents
(
[name],
entity_type_cd,
ident_status,
case_id,
import_id
)
SELECT
[name],
entityTypeCd,
identStatus,
caseId,
importId
FROM #tmpCases;
-插入第二张表
MERGE case_to_case_ident AS cc
USING (
case_idents ci
INNER JOIN #tmpCases t
ON ci.import_id = t.importId
)
ON ci.case_ident_id = cc.case_ident_id
WHEN NOT MATCHED THEN
INSERT
(
case_id,
case_ident_id,
case_status_cd,
case_ident_status_cd
)
VALUES
(
ci.case_id,
ci.case_ident_id,
t.caseStatusCd,
ci.ident_status
);