Pretius: strategiczna fuzja jako odpowiedź na współczesne wyzwania
Pretius. Budujemy mądrzej:
strategiczna fuzja jako odpowiedź na współczesne wyzwania

Jak łatwo parsować pliki JSON do tabel bazy danych Oracle: krótki przewodnik

Tomáš Kucharzyk

Oracle APEX Developer

  • 17 października, 2024

Spis

[Uwaga] Ten artykuł został pierwotnie przygotowany w języku angielskim i został przetłumaczony na język polski.

W moim poprzednim artykule opisałem moje pierwsze spotkanie z nową funkcjonalnością Oracle Database 23ai o nazwie JSON-Relational Duality Views. Ta funkcja jest szczególnie przydatna do parsowania lub tworzenia obiektów JSON w bazie danych Oracle. Dzisiaj napiszę własną procedurę, aby uczynić parsowanie JSON jeszcze łatwiejszym.

Rozwiązanie problemu

Moim zdaniem pisanie własnej procedury ma sens, jeśli masz do czynienia z małymi obiektami JSON o prostej hierarchii. Jeśli jednak używasz JSON często i musisz utrzymywać wiele typów zdefiniowanych przez użytkownika (User-defined types) oraz widoków duality views, warto stworzyć procedurę typu „szwajcarski scyzoryk”, która wykona pracę za Ciebie.

Tabele, na których będę pracować podczas pisania tego artykułu, to przykłady tabel Project Milestones z narzędzia Quick SQL w APEX.

Obraz pokazujący przykład.

Typowa reprezentacja projektu w formacie JSON będzie miała główny obiekt JSON z kilkoma atrybutami oraz tablice (arrays) dla kamieni milowych (milestones), załączników (attachments), linków i elementów akcji (action items).

{
  "projects": [
    {
      "id": "1",
      "name": "Pharmacy project",
      "owner": "Tomas",
      "created_by": "TK",
      "links": [
        {
          "name": "Rachel Morris",
          "url": "http://datefjo.do/memwez"
        }
      ],
      "action_items": [
        {
          "project_id": "1",
          "action": "Action 2",
          "the_desc": "N/A",
          "owner": "N/A",
          "status": "completed"
        }
      ],
      "milestones": [
        {
          "project_id": "1",
          "name": "Milestone 4",
          "status": "completed",
          "owner": "N/A",
          "started_date": "01.02.2024",
          "closed_date": "01.04.2024"
        }
      ],
      "attachments": [
        {
          "project_id": "1",
          "contributed_by": "TK"
        }
      ]
    }
  ]
}

Tworzenie procedury

Zanim zacznę kodować procedurę, chcę ustalić kryteria, które zamierzam spełnić.

  • Dane wejściowe procedury będą po prostu formatem JSON
  • Parsowanie hierarchicznego JSON reprezentującego wiele tabel
  • Automatyczne pobieranie i walidacja nazw tabel oraz kolumn
  • Wstawianie danych do tabel w porządku hierarchicznym

Stworzyłem diagram kroków niezbędnych do sparsowania JSON do tabel. Możesz go zobaczyć poniżej.

Obraz pokazujący diagram.

Struktura JSON i walidacja

Najpierw używam funkcji JSON_DATAGUIDE, aby pobrać strukturę wejściowego JSON. Następnie uruchamiam kilka zapytań, aby sprawdzić, czy tabele (tablice) istnieją w bazie danych i wstawiam wszystkie informacje do własnej tabeli json_structure_to_process.

Tabela będzie przechowywać dla mnie strukturę, więc nie muszę wielokrotnie odpytywać wejściowego JSON, jeśli zajdzie taka potrzeba.

Przetwarzanie struktury i danych

W następnym kroku biorę najwyższy obiekt w hierarchii, którym w moim przypadku jest tablica „projects”.

Uruchamiam prostą pętlę (loop), w której tworzę dynamiczne zapytanie SQL generujące insert z selectem z funkcji JSON_TABLE. Zapytanie dla tabeli projects wygląda tak jak poniżej.

insert into projects (id,name,owner,created_by) 
select * 
from json_table('input_json','$.projects[*]' 
    columns (
        id         VARCHAR2(11) PATH '$.id',
        name       VARCHAR2(26) PATH '$.name',
        owner      VARCHAR2(18) PATH '$.owner',
        created_by VARCHAR2(12) PATH '$.created_by'
    )
);

Po wykonaniu tego zapytania pętla wychwyci podrzędne tablice (tabele) i stworzy dla nich podobne inserty.

W moim przypadku pozostałe tablice to Links, Action items, Milestones oraz Attachments. Zapytania utworzone przez procedurę znajdują się poniżej.

--Links
insert into links (url,name) 
select * 
from json_table('input_json','$.projects.links[*]' 
    columns (
        url  VARCHAR2(42) PATH '$.url',
        name VARCHAR2(26) PATH '$.name'
    )
);
--Action items
insert into action_items (owner,action,status,the_desc,project_id) 
select * 
from json_table('input_json','$.projects.action_items[*]' 
    columns (
        owner      VARCHAR2(14) PATH '$.owner',
        action     VARCHAR2(18) PATH '$.action',
        status     VARCHAR2(26) PATH '$.status',
        the_desc   VARCHAR2(14) PATH '$.the_desc',
        project_id VARCHAR2(11) PATH '$.project_id'
    )
);
--Milestones
insert into milestones (name,owner,status,project_id,closed_date,started_date)
select * 
from json_table('input_json','$.projects.milestones[*]' 
    columns (
        name         VARCHAR2(26) PATH '$.name',
        owner        VARCHAR2(14) PATH '$.owner',
        status       VARCHAR2(26) PATH '$.status',
        project_id   VARCHAR2(11) PATH '$.project_id',
        closed_date  DATE         PATH '$.closed_date',
        started_date DATE         PATH '$.started_date'
    )
);
--Attachments
insert into attachments (project_id,contributed_by) 
select * 
from json_table('input_json','$.projects.attachments[*]' 
    columns (
        project_id     VARCHAR2(11) PATH '$.project_id',
        contributed_by VARCHAR2(12) PATH '$.contributed_by'
    )
);

Większość moich kolumn to VARCHAR2, ale prawdopodobnie możesz użyć dowolnego typu kolumny, ponieważ typ jest automatycznie wykrywany przez JSON_DATAGUIDE. Zawsze możesz dopracować swoją procedurę, aby była bardziej precyzyjna, jeśli potrzebujesz konkretnego typu danych.

Po przejściu przez wszystkie obiekty w JSON i wstawieniu wszystkich danych, pętla kończy działanie.

Wady i komplikacje

Jak zapewne zauważyłeś, największą wadą tego rozwiązania jest prawdopodobnie wymóg, aby nazwy tablic i kolumn odpowiadały nazwom właściwych tabel i kolumn. Jednak zawsze możesz użyć funkcji dopasowującej (matching function), która nie będzie wymagała 100% dokładności nazw.

Innym ograniczeniem jest wydajność. Przetwarzanie dużego wejściowego JSON ze skomplikowaną hierarchią zajmie dużo czasu.

Zalety i korzyści

Największą zaletą używania tej własnej procedury jest czas zaoszczędzony podczas tworzenia i utrzymywania User-defined types lub JSON duality views. To rozwiązanie pozwala po prostu wrzucić JSON do procedury bez żadnego wcześniejszego przygotowania czy mapowania (mapping).

Zatem to zależy od tego, który czas cenisz bardziej: czas pracy procedury, która sparsuje JSON, czy czas spędzony na development i utrzymanie.

Gadanie nic nie kosztuje, pokaż mi kod!

Cały kod, którego użyłem w tym artykule, jest dostępny tutaj. Procedura jest bardzo prosta i nie poświęciłem na nią dużo czasu. Jeśli zdecydujesz się użyć jej do własnych potrzeb, możesz potrzebować pewnych modyfikacji tu i ówdzie, aby dostosować ją do konkretnych wymagań. Daj mi znać, co myślisz o tym rozwiązaniu! I dziękuję za przeczytanie mojego artykułu. Jeśli interesują Cię tego typu treści, sprawdź inne moje publikacje na blogu Pretius:

  1. Oracle Database 23ai: JSON-Relational Duality Views and the ORA-42647 error
  2. A beginner’s guide to using Chart Patterns in Oracle APEX
  3. Oracle APEX Testing with Chrome Recorder, Puppeteer, and Lighthouse Audit
  4. Build a train reservation system using Oracle APEX and Pretius Drawing Plugin
  5. Pretius Drawing Plugin: Free office layout planner for Oracle APEX apps

Szukasz firmy tworzącej oprogramowanie?

Pracuj z zespołem, który pomógł już dziesiątkom rynkowych liderów. Umów spotkanie, by dowiedzieć się:

  • Jak działają nasze produkty
  • Jak możesz oszczędzić czas i pieniądze
  • Czym nasze rozwiązania różnią się od konkurencji

Przebieg kontaktu z Pretius

Dbamy o bezpieczeństwo Twoich danych: Certyfikat ISO

Działamy zgodnie z normą ISO 27001, zapewniając najwyższy poziom bezpieczeństwa Twoich danych.
certified dekra 27001
© 2026 Pretius. All right reserved.