Je souhaite analyser une chaîne JSON qui se trouve dans la colonne CLOB de la table Tests_1 et l'insérer dans une autre table (Test_2).
Comment puis-je faire cela en PL/SQL sans utiliser aucune bibliothèque JSON?
create table Tests_1
(
value CLOB
)
create table Test_2 (a date,b date,c number,d number, e number)
INSERT INTO Tests_1
(value)
VALUES
('{
"a":"01/01/2015",
"b":"31/12/2015",
"c":"11111111111",
"d":"1111111111",
"e":"1234567890"
}');
Oracle 12c prend en charge JSON
si vous avez une table existante faites simplement
ALTER TABLE table1 ADD CONSTRAINT constraint_name CHECK (your_column IS json);
SELECT t.your_column.id FROM table1 t;
Notez que pour quelque raison que ce soit t
nickname est nécessaire ici
Ou exemple complet:
CREATE TABLE json_documents (
id RAW(16) NOT NULL,
data CLOB,
CONSTRAINT json_documents_pk PRIMARY KEY (id),
CONSTRAINT json_documents_json_chk CHECK (data IS JSON)
);
INSERT INTO json_documents (id, data)
VALUES (SYS_GUID(),
'{
"FirstName" : "John",
"LastName" : "Doe",
"Job" : "Clerk",
"Address" : {
"Street" : "99 My Street",
"City" : "My City",
"Country" : "UK",
"Postcode" : "A12 34B"
},
"ContactDetails" : {
"Email" : "[email protected]",
"Phone" : "44 123 123456",
"Twitter" : "@johndoe"
},
"DateOfBirth" : "01-JAN-1980",
"Active" : true
}');
SELECT a.data.FirstName,
a.data.LastName,
a.data.Address.Postcode AS Postcode,
a.data.ContactDetails.Email AS Email
FROM json_documents a;
FIRSTNAME LASTNAME POSTCODE EMAIL
--------------- --------------- ---------- -------------------------
Jayne Doe A12 34B [email protected]
John Doe A12 34B [email protected]
2 rows selected.
Plus d'informations
Avec la version 11.0.4 (il n'y a pas de version 11.0.4, bien sûr) vous avez au moins deux choix (à part écrire un analyseur vous-même):
En fonction de la version du SGBDR que vous utilisez, voici quelques options:
Premièrement: pour Oracle 11.1.0.7
et plus, installez Apex 5 et utilisez le paquetage apex_json
:
-- here I have 12.1.0.1 version with version 5 of apex installed
column ora_version format a21;
column apex_version format a21;
select (select version from v$instance) as ora_version
, (select version_no from apex_release) as apex_version
from dual;
--drop table test_2;
/* our test table */
create table test_2(
c_a date,
c_b date,
c_c number,
c_d number,
c_e number
);
select * from test_2;
declare
l_json_doc clob;
begin
dbms_output.put_line('Parsing json...');
l_json_doc := '{"a":"01/01/2015","b":"31/12/2015",
"c":"11111111111","d":"1111111111",
"e":"1234567890"}';
apex_json.parse(l_json_doc);
insert into test_2(c_a, c_b, c_c, c_d, c_e)
values(apex_json.get_date(p_path=>'a', p_format=>'dd/mm/yyyy'),
apex_json.get_date(p_path=>'b', p_format=>'dd/mm/yyyy'),
to_number(apex_json.get_varchar2(p_path=>'c')),
to_number(apex_json.get_varchar2(p_path=>'d')),
to_number(apex_json.get_varchar2(p_path=>'e')));
commit;
dbms_output.put_line('Done!');
end;
/
column c_c format 99999999999;
select to_char(c_a, 'dd/mm/yyyy') as c_a
, to_char(c_b, 'dd/mm/yyyy') as c_b
, c_c
, c_d
, c_e
from test_2;
Résultat:
ORA_VERSION APEX_VERSION
--------------------- ---------------------
12.1.0.1.0 5.0.2.00.07
1 row selected.
Table created.
no rows selected.
Parsing json...
Done!
PL/SQL procedure successfully completed.
C_A C_B C_C C_D C_E
---------- ---------- ------------ ---------- ----------
01/01/2015 31/12/2015 11111111111 1111111111 1234567890
1 row selected.
Deuxièmement: Utilisez opensource PL/JSON . Jamais utilisé auparavant, alors je saisis cette occasion pour l'essayer. C'est assez similaire à apex_json
.
declare
l_json json; --json object
l_json_doc clob;
begin
dbms_output.put_line('Parsing json...');
-- parsing is done upon object instantiation
l_json_doc := '{"a":"01/01/2015","b":"31/12/2015",
"c":"11111111111","d":"1111111111",
"e":"1234567890"}';
l_json := json(l_json_doc);
insert into test_2(c_a, c_b, c_c, c_d, c_e)
values(to_date(l_json.get('a').get_string, 'dd-mm-yyyy'),
to_date(l_json.get('b').get_string, 'dd-mm-yyyy'),
to_number(l_json.get('c').get_string),
to_number(l_json.get('d').get_string),
to_number(l_json.get('e').get_string));
commit;
dbms_output.put_line('Done!');
end;
column c_c format 99999999999;
select to_char(c_a, 'dd/mm/yyyy') as c_a
, to_char(c_b, 'dd/mm/yyyy') as c_b
, c_c
, c_d
, c_e
from test_2;
Résultat:
C_A C_B C_C C_D C_E
---------- ---------- ------------ ---------- ----------
01/01/2015 31/12/2015 11111111111 1111111111 1234567890
01/01/2015 31/12/2015 11111111111 1111111111 1234567890
2 rows selected.
L’introduction de json_table()
dans la version 12.1.0.2 simplifie l’analyse JSON (pour des raisons de démonstration):
insert into test_2
select to_date(c_a, 'dd-mm-yyyy')
, to_date(c_b, 'dd-mm-yyyy')
, c_c
, c_d
, c_e
from json_table('{"a":"01/01/2015",
"b":"31/12/2015",
"c":"11111111111",
"d":"1111111111",
"e":"1234567890"}'
, '$'
columns (
c_a varchar2(21) path '$.a',
c_b varchar2(21) path '$.b',
c_c varchar2(21) path '$.c',
c_d varchar2(21) path '$.d',
c_e varchar2(21) path '$.e'
)) ;
résultat:
select *
from test_2;
C_A C_B C_C C_D C_E
----------- ----------- ---------- ---------- ----------
1/1/2015 12/31/2015 1111111111 1111111111 1234567890
Puisque vous avez spécifié que vous ne souhaitiez utiliser aucune bibliothèque JSON, si le format est corrigé, vous pouvez le convertir en quelque chose que vous pouvez analyser en tant que XML, en commençant par supprimer les accolades, en remplaçant les deux points par des signes égal, puis en supprimant le double. citations de la première partie de chaque paire nom/valeur:
select regexp_replace(regexp_replace(value, '(^{|}$)'),
'^"(.*)":(".*")($|,)', '\1=\2', 1, 0, 'm')
from tests_1;
REGEXP_REPLACE(REGEXP_REPLACE(VALUE,'(^{|}$)'),'^"(.*)":(".*")($|,)','\1=\2',1,0
--------------------------------------------------------------------------------
a="01/01/2015"
b="31/12/2015"
c="11111111111"
d="1111111111"
e="1234567890"
que vous pouvez utiliser comme attributs d’un nœud XML factice; convertissez cela en XMLType et vous pouvez utiliser XMLTable pour extraire les attributs:
select x.a, x.b, x.c, x.d, x.e
from tests_1 t
cross join xmltable('/tmp'
passing xmltype('<tmp ' ||regexp_replace(regexp_replace(value, '(^{|}$)'),
'^"(.*)":(".*")($|,)', '\1=\2', 1, 0, 'm') || ' />')
columns a varchar2(10) path '@a',
b varchar2(10) path '@b',
c number path '@c',
d number path '@d',
e number path '@e'
) x;
A B C D E
---------- ---------- ------------- ------------- -------------
01/01/2015 31/12/2015 11111111111 1111111111 1234567890
Ensuite, vous pouvez convertir les chaînes en dates lors de l'insertion:
insert into test_2 (a, b, c, d, e)
select to_date(x.a, 'DD/MM/YYYY'), to_date(x.b, 'DD/MM/YYYY'), x.c, x.d, x.e
from tests_1 t
cross join xmltable('/tmp'
passing xmltype('<tmp ' || regexp_replace(regexp_replace(value, '(^{|}$)'),
'^"(.*)":(".*")($|,)', '\1=\2', 1, 0, 'm') || ' />')
columns a varchar2(10) path '@a',
b varchar2(10) path '@b',
c number path '@c',
d number path '@d',
e number path '@e'
) x;
select * from test_2;
A B C D E
---------- ---------- ------------- ------------- -------------
2015-01-01 2015-12-31 11111111111 1111111111 1234567890
Cela permettra d'éviter que certaines paires nom/valeur ne soient présentes et vous obtiendrez des valeurs NULL si cela se produit.
Si toutes les paires sont toujours présentes, vous pouvez simplement marquer la chaîne et extraire les parties appropriées:
select to_date(regexp_substr(value, '[^"]+', 1, 4), 'DD/MM/YYYY') as a,
to_date(regexp_substr(value, '[^"]+', 1, 8), 'DD/MM/YYYY') as b,
to_number(regexp_substr(value, '[^"]+', 1, 12)) as c,
to_number(regexp_substr(value, '[^"]+', 1, 16)) as d,
to_number(regexp_substr(value, '[^"]+', 1, 20)) as e
from tests_1;
A B C D E
---------- ---------- ------------- ------------- -------------
2015-01-01 2015-12-31 11111111111 1111111111 1234567890
De Oracle 18c vous pouvez utiliser opérateur TREAT AS JSON :
Améliorations SQL pour JSON
Vous pouvez spécifier qu'une expression SQL donnée renvoie des données JSON en utilisant TREAT (... AS JSON).
TREAT (... AS JSON) vous permet de spécifier que la valeur de retour d'une expression SQL donnée doit être traitée comme une donnée JSON. De telles expressions peuvent inclure des appels de fonction PL/SQL et des colonnes spécifiées par une clause SQL WITH. Les nouvelles vues de guide de données facilitent l'accès aux informations de chemin et de type pour les champs JSON, qui sont enregistrées pour les guides de données sauvegardés par index. Le renvoi de données JSON générées et interrogées dans des instances LOB élargit la portée de l'utilisation des données relationnelles.
Cet opérateur fournit un moyen d'informer la base de données que le contenu d'un VARCHAR2, BLOB, CLOB doit être traité comme contenant du JSON. Ceci active un certain nombre de fonctionnalités utiles, notamment la possibilité d'utiliser la "syntaxe simplifiée" sur des objets de base de données dépourvus de contrainte "IS JSON".
Et dans votre exemple:
create table Test_1(val CLOB);
create table Test_2(a date,b date,c number,d number, e number);
INSERT INTO Test_1(val)
VALUES('{
"a":"01/01/2015",
"b":"31/12/2015",
"c":"11111111111",
"d":"1111111111",
"e":"1234567890"
}');
INSERT INTO Test_2(a,b,c,d,e)
SELECT sub.val_as_json.a,
sub.val_as_json.b,
sub.val_as_json.c,
sub.val_as_json.d,
sub.val_as_json.e
FROM (SELECT TREAT(val as JSON) val_as_json
FROM Test_1) sub;
COMMIT;