Разбор полного JSON в SQL - PullRequest
       6

Разбор полного JSON в SQL

0 голосов
/ 30 октября 2019

У меня есть следующий JSON (только пара узлов для целей отображения):

[{"CareNotes":[{"CareNoteID":"34289e11-6433-4020-9734-224eb8caa11a","CareNoteExtendedID":"00000000-0000-0000-0000-000000000000","ADLName":"Mobility","FlagsText":"","Note":"Help with walking, used as four wheel walker, was content.","AnswerType":1,"Fragment":"Help with walking","RemedialText":null,"Details":null,"ServiceUserID":"bc300962-3653-491a-9ba9-afab10964af4","ServiceUser":"Betty Test","ServiceUserLastName":"Test","ServiceUserForeNames":"Betty","ServiceUserDateofBirth":"19/03/1901","ServiceUserLocation":15,"WorkerID":"53e6c7b9-2c80-451e-ba8c-abfb309380ac","Worker":"Beth Beth","VoidedByWorker":null,"_supersedeStackID":null,"SupersededByWorker":null,"WorkerLastName":"Beth","DisplayOnShiftHandover":0,"WorkerInitials":"B.B.","SliderData":"Walk","SliderData2":"Not entered","SliderIcons":[{"IconID":1093,"CareNoteText":"was content"},{"IconID":1156,"CareNoteText":"used as four wheel walker"}],"DateDone":"2019-09-30T21:24:41.994+00:00","DateDoneSU":"2019-09-30T21:24:41.994+00:00","Duration":"9 minutes","DurationInt":9,"ActionIconID":6001,"mraCareOrder":5000,"wasPlanned":false,"qrVerified":false,"qrData":null,"nfcVerified":null,"inVerified":null,"ViaMonitor":null}]}]

Я не особенно хорош в SQL и неистово переучиваю то, что делал в универе и на старой работе 13 летназад, чтобы завершить проект, который берет данные JSON из API-интерфейса решения для управления уходом, в мое приложение Delphi, которое затем обрабатывает данные для обработки того и другого. Формат JSON различается в зависимости от отчета, и в случае CareNotesReport создается вышеуказанный JSON.

Мое приложение Delphi извлекает этот JSON дословно и выводит его в файл .json сЗапрос ADO, который затем выполняет следующий код (наряду с некоторыми другими запросами выбора, которые здесь не имеют отношения):

use CMUtility;


DECLARE @JSON VARCHAR(MAX)

SELECT @JSON = BulkColumn
FROM OPENROWSET 
(BULK 'C:\Users\User\Documents\Embarcadero\Studio\Projects\CMU\Win32\Debug\carenotesreport.json', SINGLE_CLOB) 
AS j

drop table if exists jsoncarenotes

select * into JSONCareNotes
from OPENJSON(@JSON,'$.CareNotes')
with (
    DateDone nvarchar(10) '$.DateDone',
    ServiceUser nvarchar(100) '$.ServiceUser',
    ServiceUserLastName nvarchar(50) '$.ServiceUserLastName',
    SUDOB nvarchar(15) '$.ServiceUserDateofBirth',
    Note nvarchar(255) '$.Note',
    ADLName nvarchar(200) '$.ADLName',
    FlagsText nvarchar(255) '$.FlagsText',
    Fragment nvarchar(255) '$.Fragment',
    RemedialText nvarchar(255) '$.RemedialText',
    Worker nvarchar(30) '$.Worker',
    ServiceUserID nvarchar(100) '$.ServiceUserID',
    WorkerID nvarchar(100) '$.WorkerID',
    CareNoteID nvarchar(255) '$.CareNoteID',
    SID1 nvarchar(255) '$.SliderIcons[0].IconID',
    SText1 nvarchar(255) '$.SliderIcons[0].CareNoteText',
    SID2 nvarchar(255) '$.SliderIcons[1].IconID',
    SText2 nvarchar(255) '$.SliderIcons[1].CareNoteText',
    SID3 nvarchar(255) '$.SliderIcons[2].IconID',
    SText3 nvarchar(255) '$.SliderIcons[2].CareNoteText',
    SID4 nvarchar(255) '$.SliderIcons[3].IconID',
    SText4 nvarchar(255) '$.SliderIcons[3].CareNoteText',
    SID5 nvarchar(255) '$.SliderIcons[4].IconID',
    SText5 nvarchar(255) '$.SliderIcons[4].CareNoteText'
    )
    as CareNotes

У меня есть пара проблем. С помощью приведенного выше кода мне пришлось удалить первые [и] из файла JSON, чтобы заставить его работать, но из-за размера некоторых возвратов мне пришлось изменить использование потока памяти на поток файлов в Delphi. ,Это создало проблему в том, что, хотя я могу обрезать последний] файла, я до сих пор не могу найти надежный (и простой) способ обрезки первого [. Поэтому я вынужден сделать вывод, что слабым звеном является мой код SQL, и что он должен иметь возможность обрабатывать JSON с этими двумя символами.

Пожалуйста, кто-нибудь может показать мне, где яЯ иду не так. Я знаю, что исходный JSON выглядит как массив, объект, массив, объект, но я не знаю, что из этого сделать. Кроме того, я обманул способность читать SliderIcons, поскольку знаю, что в этом массиве максимум 5 объектов, но предпочел бы более динамичное решение, если это возможно.

Будем весьма благодарны за любую помощь, предоставленную с точки зрения способа удаления этого первого [в Delphi, или лучшего SQL для обработки исходного JSON.

С уважением, Муравей

1 Ответ

1 голос
/ 31 октября 2019

Вы можете проанализировать этот JSON ввод, используя возможности SQL Server. Если ваш JSON ввод имеет этот фиксированный формат (массив с одним элементом и вложенными JSON массивами), вам нужен дополнительный оператор APPLY с вызовом OPENJSON() для анализа вложенного массива JSON. Обратите внимание, что когда указанное свойство содержит внутренний объект или массив JSON, вам необходимо использовать опцию AS JSON в определении столбца.

JSON:

DECLARE @json nvarchar(max)

--SELECT @json = BulkColumn
--FROM OPENROWSET (BULK 'C:\Users\User\Documents\Embarcadero\Studio\Projects\CMU\Win32\Debug\carenotesreport.json', SINGLE_CLOB) AS j

SELECT @json = N'[
   {
      "CareNotes":[
         {
            "CareNoteID":"34289e11-6433-4020-9734-224eb8caa11a",
            "CareNoteExtendedID":"00000000-0000-0000-0000-000000000000",
            "ADLName":"Mobility",
            "FlagsText":"",
            "Note":"Help with walking, used as four wheel walker, was content.",
            "AnswerType":1,
            "Fragment":"Help with walking",
            "RemedialText":null,
            "Details":null,
            "ServiceUserID":"bc300962-3653-491a-9ba9-afab10964af4",
            "ServiceUser":"Betty Test",
            "ServiceUserLastName":"Test",
            "ServiceUserForeNames":"Betty",
            "ServiceUserDateofBirth":"19/03/1901",
            "ServiceUserLocation":15,
            "WorkerID":"53e6c7b9-2c80-451e-ba8c-abfb309380ac",
            "Worker":"Beth Beth",
            "VoidedByWorker":null,
            "_supersedeStackID":null,
            "SupersededByWorker":null,
            "WorkerLastName":"Beth",
            "DisplayOnShiftHandover":0,
            "WorkerInitials":"B.B.",
            "SliderData":"Walk",
            "SliderData2":"Not entered",
            "SliderIcons":[
               {
                  "IconID":1093,
                  "CareNoteText":"was content"
               },
               {
                  "IconID":1156,
                  "CareNoteText":"used as four wheel walker"
               }
            ],
            "DateDone":"2019-09-30T21:24:41.994+00:00",
            "DateDoneSU":"2019-09-30T21:24:41.994+00:00",
            "Duration":"9 minutes",
            "DurationInt":9,
            "ActionIconID":6001,
            "mraCareOrder":5000,
            "wasPlanned":false,
            "qrVerified":false,
            "qrData":null,
            "nfcVerified":null,
            "inVerified":null,
            "ViaMonitor":null
         }
      ]
   }
]'

Оператор:

SELECT 
    j1.DateDone,
    j1.Note,
    j2.IconID,
    j2.CareNoteText
--INTO JSONCareNotes    
FROM OPENJSON(@json, '$[0].CareNotes') WITH (
    DateDone nvarchar(10) '$.DateDone',
    Note nvarchar(255) '$.Note',
    -- add additional columns definitons
    SliderIcons nvarchar(max) AS JSON
) j1
CROSS APPLY OPENJSON(j1.SliderIcons) WITH (
   IconID int '$.IconID',
   CareNoteText nvarchar(100) '$.CareNoteText'
) j2

Результат:

DateDone    Note                                                        IconID  CareNoteText
2019-09-30  Help with walking, used as four wheel walker, was content.  1093    was content
2019-09-30  Help with walking, used as four wheel walker, was content.  1156    used as four wheel walker

Примечания (JSON основы):

  • Когда вы хотите проанализировать JSON строку и получить результаты в виде таблицы, используйте OPENJSON табличную функцию с заданной по умолчанию или явной схемой.
  • Функция JSON_QUERY извлекает объект или массив из строки JSON. Если значение не является объектом или массивом, результатом будет NULL в режиме lax и ошибка в режиме strict.
  • Функция JSON_VALUE извлекает скалярное значение изJSON строка. Если path указывает на не скалярное значение, результатом будет NULL в режиме lax и ошибка в режиме strict

Примечания (Delphi и SQL Server):

  • Вы можете организовать свою логику как хранимую процедуру, которая имеет один параметр - текст JSON. В этой ситуации вы отправите JSON непосредственно на SQL Server, и использование OPENROWSET() не понадобится (OPENJSON() нужны дополнительные разрешения ).
  • Выполнениехранимая процедура с Delphi - простая задача, например, с использованием ADO.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...