Получить массив значений вместо массива объектов при использовании FOR JSON
Я пытаюсь сгладить массив объектов, который построен FOR JSON
,
Мой запрос выглядит так:
select
(
select id from MyTable
where id in (select value from OPENJSON(@jsonArray))
FOR JSON PATH
) existing,
(
select value id from OPENJSON(@jsonArray)
where value not in (select Id from MyTable)
FOR JSON PATH
) missing
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
Результирующий JSON:
{
"existing": [
{
"id": "a00cd8f6-d1c6-4604-b235-59d3cacd5bcc"
},
{
"id": "052455b6-6bf5-47d3-8bee-7ba98d7fbd50"
}
],
"missing": [
{
"id": "328add2d-e8f2-4a0e-af54-5b1733310170"
}
]
}
Вместо этого я бы хотел:
{
"existing": [
{
"id": "a00cd8f6-d1c6-4604-b235-59d3cacd5bcc"
},
{
"id": "052455b6-6bf5-47d3-8bee-7ba98d7fbd50"
}
],
"missing": [
"328add2d-e8f2-4a0e-af54-5b1733310170"
]
}
Отсутствующий массив не должен содержать json-объекты, только значения. Какие-либо предложения?
2 ответа
Если вы используете SQL Server 2017, вы можете создать свой массив с JSON_QUERY
а также STRING_AGG
(с SQL Server 2016 вы не можете использовать STRING_AGG
, так что вам придется немного поработать над estra, но следующая идея будет по-прежнему верна):
declare @missing table(id varchar(max))
declare @existing table(id varchar(max))
insert into @missing values ('a00cd8f6-d1c6-4604-b235-59d3cacd5bcc')
insert into @missing values ('052455b6-6bf5-47d3-8bee-7ba98d7fbd50')
insert into @existing values ('328add2d-e8f2-4a0e-af54-5b1733310170')
select
(
select id from @missing
FOR JSON PATH
) existing,
(
select JSON_QUERY(concat('[' , STRING_AGG(concat('"' , STRING_ESCAPE(id, 'json') , '"'),',') , ']'))
from @existing
) missing
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
Результат:
{
"existing": [
{
"id": "a00cd8f6-d1c6-4604-b235-59d3cacd5bcc"
},
{
"id": "052455b6-6bf5-47d3-8bee-7ba98d7fbd50"
}
],
"missing": [
"328add2d-e8f2-4a0e-af54-5b1733310170"
]
}
Использовать добавление от курсора
DECLARE @missing nvarchar(max),
@json nvarchar(max) = (select
(
select id from MyTable
where id in (select value from OPENJSON(@jsonArray))
FOR JSON PATH
) existing
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)
DECLARE missing_cursor CURSOR FOR
select value id
from OPENJSON(@jsonArray)
where value not in (select Id from MyTable)
OPEN missing_cursor
FETCH NEXT FROM missing_cursor
INTO @missing
WHILE @@FETCH_STATUS = 0
BEGIN
SET @json = JSON_MODIFY(@json,'append $.missing', @missing)
FETCH NEXT FROM missing_cursor
INTO @missing
END
CLOSE missing_cursor;
DEALLOCATE missing_cursor;
select @json
Это не так просто, как должно быть...
AFAIK нет способа создать голый массив json с sql-сервером. Но вы можете обмануть это на строковом уровне:
DECLARE @exist TABLE(id VARCHAR(100));
DECLARE @miss TABLE(id VARCHAR(100));
INSERT INTO @exist VALUES ('exist1'),('exist2');
INSERT INTO @miss VALUES ('miss1'),('miss2');
- Это создаст массив объектов, который вы хотите
SELECT id FROM @exist
FOR JSON PATH
- И это создаст голый массив, используя несколько довольно уродливых уловок.
SELECT REPLACE(REPLACE(REPLACE(
(
SELECT id from @miss
FOR JSON PATH
),'"id":',''),'{',''),'}','')
- Теперь мы должны объединить оба. И снова нам нужен трюк. Мы используем JSON_QUERY()
на литерале JSON, чтобы избежать кавычек.
SELECT
(
SELECT id FROM @exist
FOR JSON PATH
) AS existing
,JSON_QUERY(
REPLACE(REPLACE(REPLACE(
(
SELECT id from @miss
FOR JSON PATH
),'"id":',''),'{',''),'}','')
) AS missing
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER;
Это результат
{
"existing":[{"id":"exist1"},{"id":"exist2"}] <--array of objects
,"missing":["miss1","miss2"] <--array of naked values
}
Я понятия не имею, почему это не может быть сделано из коробки...