背景
Oracleから数千行をフェッチし、SlickGridで使用するためにJSONに変換する必要があります。現在、PHPで行をフェッチし、iconvでISOからUTF-8に変換し、json_encodeでjsonにエクスポートしています。操作全体は、DB側で約1秒かかり、JSONを生成するのに5秒かかります。長い道のりです。
質問
Oracle 12cはJSONをサポートしていることを読みましたが、必要なものが正確に見つかりません。
Json形式で標準のSQLクエリの結果を返す方法はありますか?
おそらく私はこれに似たクエリを発行したいと思います:
SELECT * from table AS JSON
次のような有効なjsonを受け取ります。
[{"col1": "value1", "col2": 2}, {"col1": "valueOfRow2", "col2": 3}]
重要なことは、クライアント側でISO-8859-2文字セットを使用し、JSONがUTF-8であるか、シーケンスをエスケープする必要があるため、Unicodeシーケンスをエスケープする必要があることです。
Oracle 12cバージョン12.1.0.2(2014年11月11日現在の最新バージョン)は、JSONサポートを追加します。 https://docs.Oracle.com/database/121/NEWFT/chapter12102.htm#BGBGADCC
10月17日から利用できます。 https://blogs.Oracle.com/db/entry/Oracle_database_12c_release_1
そのバージョンでパッチを適用したり作業したりできない場合は、Lewis CunninghamとJonas Krogsboellによって書かれた優れたパッケージがあります:PL/JSON * http://pljson.sourceforge.net/
これは素晴らしいパッケージです(多くのデータベースのインストールで使用しました)。
含まれている例は優れており、ほとんどのシナリオをカバーしています。
declare
ret json;
begin
ret := json_dyn.executeObject('select * from tab');
ret.print;
end;
/
12cR2(Oracle Cloudで利用可能)はこれをネイティブにサポートします。
SQL> select JSON_ARRAY(EMPLOYEE_ID, FIRST_NAME,LAST_NAME) from HR.EMPLOYEES;
JSON_ARRAY(EMPLOYEE_ID,FIRST_NAME,LAST_NAME)
--------------------------------------------------------------------------------
[100,"Steven","King"]
[101,"Neena","Kochhar"]
または
SQL> select JSON_OBJECT('ID' is EMPLOYEE_ID , 'FirstName' is FIRST_NAME,'LastName' is LAST_NAME) from HR.EMPLOYEES;
JSON_OBJECT('ID'ISEMPLOYEE_ID,'FIRSTNAME'ISFIRST_NAME,'LASTNAME'ISLAST_NAME)
----------------------------------------------------------------------------
{"ID":100,"FirstName":"Steven","LastName":"King"}
{"ID":101,"FirstName":"Neena","LastName":"Kochhar"}
Xmltypeを使用して、SQLの結果をXMLおよびJSONに変換できます。バージョン9以降のOracleで機能するソリューションについては、次の記事を参照してください。パッケージitstar_xml_utilをダウンロードすることもできます。
http://stefan-armbruster.com/index.php/12-it/pl-sql/12-Oracle-xml-and-json-goodies
Empテーブルを使用した簡単な例:
declare
l_sql_string varchar2(2000);
l_xml xmltype;
l_json xmltype;
begin
l_sql_string := 'select a.empno, a.ename, a.job from emp a';
-- Create the XML aus SQL
l_xml := itstar_xml_util.sql2xml(l_sql_string);
-- Display the XML
dbms_output.put_line(l_xml.getclobval());
l_json := itstar_xml_util.xml2json(l_xml);
-- Display the JSON
dbms_output.put_line(l_json.getclobval());
end;
結果は次のようになります。
{"ROWSET": [
{
"EMPNO": 7839,
"ENAME": "KING",
"JOB": "PRESIDENT"
},
{
"EMPNO": 7698,
"ENAME": "BLAKE",
"JOB": "MANAGER"
},
[...]
{
"EMPNO": 7934,
"ENAME": "MILLER",
"JOB": "CLERK"
}
]}
JSONに対するOracle 12cのサポートは、JSONオブジェクトを保存し、クエリし、それらから選択する機能です。
表形式であり、データをJSONとして表示するだけです。したがって、行を単純に{'col1': 'rowN1'、 'col2': 'rowN2'}に連結し、残りをクライアント側で作成できます。または、LISTAGGを使用してドキュメント全体を取得できます。例: http://technology.amis.nl/2011/06/14/creating-json-document-straight-from-sql-query-using-listagg-and-with-clause/
SQL VARCHAR2の4000文字という制限に注意してください。
http://database-geek.com/2009/03/25/json-in-and-out-of-Oracle-json-data-type/ しかし、私はOracleオブジェクト型はパフォーマンスを改善すると考えています。
別のアプローチは、XMLTypeを使用してXMLをエクスポートすることです。次に、XMLをJSONに変換します。 XMLTypeは特殊文字を処理し、APIは非常に安定しています(Oracle 14用にプログラムを書き換える必要はありません)。
Oracle 19cを開始すると、テーブルの行のJSON表現を作成する構文 )が簡略化されました
例:hr.employees
のすべての行を個別のjsonに変換するには、次を使用します。
SELECT JSON_OBJECT(*) FROM hr.employees ;
{
"EMPLOYEE_ID" : 100,
"FIRST_NAME" : "Steven",
"LAST_NAME" : "King",
"EMAIL" : "SKING",
"PHONE_NUMBER" : "515.123.4567",
"HIRE_DATE" : "2003-06-17T00:00:00",
"JOB_ID" : "AD_PRES",
"SALARY" : 24000,
"COMMISSION_PCT" : null,
"MANAGER_ID" : null,
"DEPARTMENT_ID" : 90
} --row 1
{
"EMPLOYEE_ID" : 101,
"FIRST_NAME" : "Neena",
"LAST_NAME" : "Kochhar",
"EMAIL" : "NKOCHHAR",
"PHONE_NUMBER" : "515.123.4568",
"HIRE_DATE" : "2005-09-21T00:00:00",
"JOB_ID" : "AD_VP",
"SALARY" : 17000,
"COMMISSION_PCT" : null,
"MANAGER_ID" : 100,
"DEPARTMENT_ID" : 90
} --row 2
...
リリース12.2には、SQLクエリから直接JSONドキュメントを生成するための新しい機能が含まれています。目標を達成する最も簡単な方法は、次の関数を使用することです。 JSON_OBJECT
および JSON_ARRAYAGG
。
create table tab as
select level col1, 'value '||level col2 from dual connect by level <= 2
/
select max (rownum) rn, json_arrayagg (
json_object (
key 'col1' value col1,
key 'col2' value col2
) format json returning clob
) as json_doc
from tab;
結果:
RN JSON_DOC
---------- ---------------------------------------------------------
2 [{"col1":1,"col2":"value 1"},{"col1":2,"col2":"value 2"}]
大量のデータでテストする:
select rn, length (json_doc) json_size, json_doc from (
<query mentoined above here>
cross join (select dummy from dual connect by level <= 1e5)
);
RN JSON_SIZE JSON_DOC
---------- ---------- ---------------------------------------------------------
200000 5600001 [{"col1":1,"col2":"value 1"},{"col1":2,"col2":"value 2"},
低速のテストマシンでは、約1秒かかりました。 5,6M JSONを作成します。
リリース19cでは、関数の構文 JSON_OBJECT
は簡略化されています 。
上記のクエリは次のようになります。
select json_arrayagg (
json_object (*) returning clob
) as json_doc
from tab;
オン ライブSQL 。
Oracle 12.2の答えに追加するには、このようにjsonを作成できます。
SELECT JSON_ARRAY(
JSON_OBJECT (
KEY 'number' VALUE s.number,
KEY 'name' VALUE s.sname,
KEY 'location' VALUE s.loc
)
) AS student_det
FROM student s;
これを試してください:
:)人生は幸せです
with data as
( select
xmlelement(e,regexp_replace('{"name":"'||colname||'"}', '[[:cntrl:]]', ''),',') col1
from tblname
)
select
rtrim(replace(replace(replace(xmlagg(col1).getclobval(),'&'||'quot;','"'),'<E>',''),'</E>',''),',')
as very_long_json
from data;