#sql #json #sql-server
Вопрос:
У меня есть следующий JSON:
[
{
"UserDetails": [
{
"UserName": "User1",
"UserDateOfBirth": "06/11/89",
"UserID": "12345",
"NotesDay1": [
{
"NoteID": "a287fcc4",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-06T00:19:14"
},
{
"NoteID": "4a48385a",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-06T02:19:59"
},
{
"NoteID": "ddb6bc52",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-06T04:14:50"
}
]
},
{
"UserName": "User2",
"UserDateOfBirth": "05/08/99",
"UserID": "23456",
"NotesDay1": [],
"NotesDay2": [
{
"NoteID": "62cf5478",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-07T01:00:48"
},
{
"NoteID": "7f864ef4",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-07T01:00:48"
},
{
"NoteID": "db1a0af0",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-07T06:28:02"
}
],
"NotesDay3": [
{
"NoteID": "2ae6b923",
"AnswerType": 1,
"RemedialText": null,
"Details": null,
"UserLocation": 0,
"DateDone": "2021-08-07T06:28:02"
}
],
"NotesDay4": [],
"NotesDay5": [],
"NotesDay6": [],
"NotesDay7": []
}
]
}
]
Мой текущий SQL-запрос для импорта настроен следующим образом:
SELECT j2.UserID, j3.NoteID1, j4.NoteID2, j5.NoteID3, j6.NoteID4, j7.NoteID5, j8.NoteID6, j9.NoteID7
INTO [UserDayNotes]
FROM OPENJSON(@JSON)
WITH
(
UserDetails nvarchar(max) '$.UserDetails' as JSON
) j1
CROSS APPLY OPENJSON(j1.UserDetails) WITH
(
UserID nvarchar(100) '$.UserID',
NotesDay1 nvarchar(max) '$.NotesDay1' as JSON,
NotesDay2 nvarchar(max) '$.NotesDay2' as JSON,
NotesDay3 nvarchar(max) '$.NotesDay3' as JSON,
NotesDay4 nvarchar(max) '$.NotesDay4' as JSON,
NotesDay5 nvarchar(max) '$.NotesDay5' as JSON,
NotesDay6 nvarchar(max) '$.NotesDay6' as JSON,
NotesDay7 nvarchar(max) '$.NotesDay7' as JSON
) j2
CROSS APPLY OPENJSON(j2.NotesDay1) WITH
(
NoteID1 nvarchar(100) '$.NoteID'
) j3
CROSS APPLY OPENJSON(j2.CareNotesDay2) WITH
(
NoteID2 nvarchar(100) '$.NoteID'
) j4
CROSS APPLY OPENJSON(j2.CareNotesDay3) WITH
(
NoteID3 nvarchar(100) '$.NoteID'
) j5
CROSS APPLY OPENJSON(j2.CareNotesDay4) WITH
(
NoteID4 nvarchar(100) '$.NoteID'
) j6
CROSS APPLY OPENJSON(j2.CareNotesDay5) WITH
(
NoteID5 nvarchar(100) '$.NoteID'
) j7
CROSS APPLY OPENJSON(j2.CareNotesDay6) WITH
(
NoteID6 nvarchar(100) '$.NoteID'
) j8
CROSS APPLY OPENJSON(j2.CareNotesDay7) WITH
(
NoteID3 nvarchar(100) '$.NoteID'
) j9
Если я выполню запрос как есть, то он будет выполняться вечно и никогда не завершится. Если я закомментирую все, кроме j2.userId, j3.NoteID1 и j4.NoteID2, то запрос выполняется более или менее мгновенно. Я предполагаю, что это как-то связано с количеством элементов перекрестного применения, которые у меня есть, но мой опыт и знания этой стороны SQL невелики, и мне действительно не помешала бы помощь.
После обсуждений ниже я понял, что у меня может быть несколько экземпляров Дня 1, Дня 2 и т.д., И поэтому более реалистичный желаемый результат будет ниже:
Идентификатор пользователя | Число дней | примечание. |
---|---|---|
Пользователь1 | 1 | a287fcc4 |
Пользователь1 | 1 | 4a48385a |
Пользователь1 | 1 | ddb6bc52 |
Пользователь2 | 2 | 62cf5478 |
Пользователь2 | 2 | 7f864ef4 |
Пользователь2 | 2 | db1a0af0 |
Пользователь2 | 3 | 2ae6b923 |
(Боже милостивый, с этим столом пришлось повозиться!)
Данные внутри каждого объекта NotesDayX являются повторением информации, хранящейся в другом месте, поэтому, пока у меня есть идентификатор примечания, я могу обойтись без другой информации, содержащейся в JSON.
Заранее спасибо.
Комментарии:
1. Итак, ваш внешний корневой объект-это массив, всегда ли у него только один индекс или несколько? Всегда ли каждое из свойств
NotesDay
массива также содержит только один объект?2.Если подумать, в этом JSON есть что-то очень странное: объект, расположенный в нем,
$[0].UserDetails[1]
также содержит свойство UserDetails, другими словами, он вложен во второй раз, в то время как первый объект-нет. Является ли этот JSON правильным примером, или где-то отсутствуют или есть дополнительные скобки?3. @Charlieface Я изменил исходный JSON, чтобы включить более анонимную структуру. В первый раз я немного упростил его для целей этого поста, и хотя он все еще немного отредактирован, структура больше похожа на то, как она выглядит полностью.
4. По сути, UserDetails-это массив с несколькими объектами, содержащими информацию о пользователе. Внутри этих объектов находится дополнительный набор массивов, которые отслеживают данные в течение 7 дней, каждый из которых называется NotesDay 1…NotesDay7. Мне действительно нужна только строка NoteID внутри каждого из них. Каждый NotesDayX может содержать несколько или не содержать объектов, указывающих на записи в этот день, основанные на различных действиях, выполняемых пользователем.
5. Хорошо, поэтому, пожалуйста, ответьте: внешний массив всегда содержит только один объект в нем? И учитывая, что в настоящее время в массиве имеется несколько объектов note
NotesDay
, как вы хотите это представить?
Ответ №1:
Вы могли бы объединить все Notes
массивы вместе.
Кроме того, неясно, всегда ли во внешнем массиве есть только один внутренний объект, если да, то мы можем использовать $[0]
и пропустить первый OPENJSON
SELECT
j1.UserID,
j2.DayNumber,
j2.NoteID
INTO [UserDayNotes]
FROM OPENJSON(@JSON, '$[0].UserDetails')
WITH
(
UserID nvarchar(100),
NotesDay1 nvarchar(max) as JSON,
NotesDay2 nvarchar(max) as JSON,
NotesDay3 nvarchar(max) as JSON,
NotesDay4 nvarchar(max) as JSON,
NotesDay5 nvarchar(max) as JSON,
NotesDay6 nvarchar(max) as JSON,
NotesDay7 nvarchar(max) as JSON
) j1
CROSS APPLY (
SELECT 1 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay1) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 2 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay2) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 3 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay3) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 4 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay4) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 5 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay5) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 6 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay6) WITH
(
NoteID nvarchar(100)
) j2
UNION ALL
SELECT 7 AS DayNumber, NoteID
FROM OPENJSON(j1.NotesDay7) WITH
(
NoteID nvarchar(100)
) j2
) j2;
Комментарии:
1. Вот и все!!! Спасибо. Я думаю, что это, вероятно, гораздо более простое и очевидное решение для большинства присутствующих здесь людей, включая вас. Но, как я уже сказал, это не моя обычная работа! Большое вам спасибо @Charlieface
Ответ №2:
..если структура json немного отличается и если в массивах userdetails и notesdayX может быть только один объект …поиграйте:
declare @j nvarchar(max) =N'
[
{"UserDetails":[
{"UserID":"User1",
"NotesDay1":[{"NoteID":"12345"}],
"NotesDay2":[],
"NotesDay3":[],
"NotesDay4":[{"NoteID":"23456"}],
"NotesDay5":[],
"NotesDay6":[{"NoteID":"34567"}],
"NotesDay7":[{"NoteID":"45678"}]
}
]},
{"UserDetails":[
{"UserID":"User2",
"NotesDay1":[{"NoteID":"54321"}],
"NotesDay2":[{"NoteID":"65432"}],
"NotesDay3":[],
"NotesDay4":[{"NoteID":"76543"}],
"NotesDay5":[],
"NotesDay6":[],
"NotesDay7":[{"NoteID":"87654"}]
}
]}
]';
select *
from openjson(@j)
with
(
userid nvarchar(100) '$.UserDetails[0].UserID',
notesday1 nvarchar(10) '$.UserDetails[0].NotesDay1[0].NoteID',
notesday4 nvarchar(10) '$.UserDetails[0].NotesDay4[0].NoteID',
notesday7 nvarchar(10) '$.UserDetails[0].NotesDay7[0].NoteID'
);
Комментарии:
1. Спасибо за ответ. Однако не будет ли это просто возвращать только первую строку моих данных JSON?
2. @Dan..если массив состоит из пользовательских данных:
[{detail1:[]}, {detail2:[]}]
.., то openjson() вернет две строки, по одной для каждой детали. в примере @json в вопросе второй пользовательский элемент вложен в первый..и для этого @json даже запрос вопроса не будет работать.3. Я проверил предложенный вами запрос, и он действительно вернул только одну строку. Исходный запрос выше не работает в сочетании с более чем 2 разными днями, но для первых двух он работал. Вот почему я застрял, лол.