We're writing WS with ORDS (Oracle Rest Data Services) and we are able to have simple (flat) json responses. ORDS automatically convert my SYS_REFCURSON in json, for example:
{
"title": "To Kill a Mockingbird",
"author": "Harper Lee",
"yearPublished": 1960,
"genre": "Fiction",
"pages": 281
}
Now we want to have some structure, for instance:
{
"title": "To Kill a Mockingbird",
"author": {
"firstName": "Harper",
"lastName": "Lee"
},
"yearFirstPublished": 1960,
"genre": "Fiction",
"editions": [
{
"yearPublished": 1960,
"publisher": "J.B. Lippincott & Co.",
"isbn": "978-0-06-112008-4",
"pages": 281,
"language": "English"
},
{
"yearPublished": 2004,
"publisher": "Time Warner",
"isbn": "978-0446310789",
"pages": 374,
"language": "English"
},
{
"yearPublished": 2015,
"publisher": " Random House UK Ltd",
"isbn": "978-1784870799",
"pages": 485,
"language": "English"
}
]
}
Here is my database structure
CREATE TABLE BOOK
(
BOOK_ID NUMBER(9) NOT NULL,
BOOK_NAME VARCHAR2(500 CHAR) NOT NULL,
AUTHOR_ID NUMBER(9) NOT NULL,
GENRE VARCHAR2(100) NOT NULL,
FIRST_PUBLISHED_YEAR NUMBER(4),
PAGES NUMBER(4)
);
CREATE TABLE AUTHOR
(
AUTHOR_ID NUMBER(9) NOT NULL,
FIRST_NAME VARCHAR2(500 CHAR) NOT NULL,
LAST_NAME VARCHAR2(500 CHAR) NOT NULL
);
CREATE TABLE EDITIONS
(
BOOK_ID NUMBER(9) NOT NULL,
YEAR_PUBLISHED NUMBER(4),
ISBN VARCHAR2(13 CHAR) NOT NULL,
PUBLISHER VARCHAR2(500 CHAR) NOT NULL,
PAGES VARCHAR2(500 CHAR) NOT NULL,
LANGUAGE VARCHAR2(50 CHAR) NOT NULL
);
The first json comes from a WS defined as a simple select:
BEGIN
ORDS.define_service(
p_module_name => 'test',
p_base_path => 'test/',
p_pattern => 'books/getBookById/:book_id',
p_method => 'GET',
p_source_type => ORDS.source_type_collection_feed,
p_source => 'select BOOK_NAME as title,
(select FIRST_NAME||'' ''||LAST_NAME from author a where a.author_id = t.author_id) as author,
FIRST_PUBLISHED_YEAR as yearPublished,
GENRE as genre,
PAGES as pages
from BOOK
where BOOK_ID = :book_id;',
p_items_per_page => 0);
COMMIT;
END;
/
Is it possibile to get the second json output (I suppose a function/procedure is needed)?
I tried to define the service using a stored procedure returning cursor, but it cannot have the "structure". May be with a procedure that firstly reads the BOOK table and then the EDITIONS one, but how to "merge" the results to achieve the second json?
Thanks, Vjncenzo
With GROUP BY or with LATERAL:
select json_object(
'title' : b.book_name,
'author' : json_object(
'firstName' : a.first_name,
'lastName' : a.last_name
),
'yearFirstPublished' : b.first_published_year,
'genre' : b.genre,
'editions' : json_arrayagg(
json_object(
'yearPublished' : e.year_published,
'publisher' : e.publisher,
'isbn' : e.isbn,
'pages' : e.pages,
'language' : e.language
)
)
RETURNING CLOB
) as "{}book"
from book b
join author a using (author_id)
join editions e using (book_id)
where book_id = :book_id
group by book_id, b.book_name, a.first_name, a.last_name,
b.first_published_year, b.genre
;
select json_object(
'title' : b.book_name,
'author' : a.author,
'yearFirstPublished' : b.first_published_year,
'genre' : b.genre,
'editions' : e.editions
RETURNING CLOB
) as "{}book"
from book b,
lateral(
select json_object(
'author' : json_object(
'firstName' : a.first_name,
'lastName' : a.last_name
)
) author
from author a where a.author_id = b.author_id
) a,
lateral (
select json_arrayagg(
json_object(
'yearPublished' : e.year_published,
'publisher' : e.publisher,
'isbn' : e.isbn,
'pages' : e.pages,
'language' : e.language
)
RETURNING CLOB
) editions
from editions e where e.book_id = b.book_id
) e
where b.book_id = :book_id
;