除了 Eat A Peach 的回答之外,我还开发了一些 INSTEAD OF 查询来插入和更新数据。它们仍在开发中,所以有点粗糙,但我想我会把它们贴在这里,以防有人发现它们很方便。
CREATE OR REPLACE VIEW FIELD_OPTIONS AS
select
s.id as space_id,
s.prefix_code,
fields.name AS FIELD_NAME,
fields.label AS FIELD_LABEL,
options.value as OPTION_VALUE,
options.label AS OPTIONS_LABEL,
options.mapping AS OPTIONS_MAPPING
FROM
metadata m,
spaces s,
XMLTABLE('/metadata/fields/field'
PASSING xmltype(m.xml_string)
COLUMNS name VARCHAR(32) PATH '@name',
label VARCHAR(64) PATH '@label',
options XMLTYPE PATH 'option') fields,
XMLTABLE('/option'
PASSING fields.options
COLUMNS value NUMBER PATH '@value',
label VARCHAR(64) PATH '.',
mapping VARCHAR(64) PATH '@mapping') options
where
s.metadata_id = m.id;
CREATE OR REPLACE TRIGGER INSERT_FIELD_OPTIONS
INSTEAD OF INSERT ON FIELD_OPTIONS
FOR EACH ROW
DECLARE
field_name VARCHAR(32);
space_prefix_code VARCHAR(32);
new_option_num NUMBER;
new_option_label VARCHAR(64);
new_option_mapping VARCHAR(64);
BEGIN
space_prefix_code:=:NEW.prefix_code;
field_name:=:NEW.field_name;
new_option_label:=:NEW.options_label;
new_option_mapping:=:NEW.options_mapping;
select --TODO: find out if options.value = 0
max(options.value)+1 INTO new_option_num
FROM
metadata m,
spaces s,
XMLTABLE('/metadata/fields/field'
PASSING xmltype(m.xml_string)
COLUMNS name VARCHAR(32) PATH '@name',
label VARCHAR(64) PATH '@label',
options XMLTYPE PATH 'option') fields,
XMLTABLE('/option'
PASSING fields.options
COLUMNS value NUMBER PATH '@value',
label VARCHAR(64) PATH '.') options
where
s.metadata_id = m.id AND
s.prefix_code = space_prefix_code AND
fields.name=field_name;
update metadata set
xml_string=(INSERTCHILDXML(XMLTYPE(xml_string),
'/metadata/fields/field[@name=''' || field_name || ''']',
'option',
XMLTYPE('<option mapping="' || new_option_mapping || '" value="' || TO_CHAR(new_option_num) || '">' || new_option_label || '</option>'))).getclobval() --must convert to clob as it is stored in the database that way
WHERE
id =(select metadata_id from spaces where prefix_code = space_prefix_code);
DBMS_OUTPUT.put_line(CHR(9) || TO_CHAR(SQL%ROWCOUNT)||' rows updated');
END;
/
CREATE OR REPLACE TRIGGER UPDATE_FIELD_OPTIONS
INSTEAD OF UPDATE ON FIELD_OPTIONS
FOR EACH ROW
DECLARE
field_name VARCHAR(32);
space_prefix_code VARCHAR(32);
new_options_label VARCHAR(64);
new_option_mapping VARCHAR(64);
new_option_value VARCHAR(64);
BEGIN
space_prefix_code:=:NEW.prefix_code;
field_name:=:NEW.field_name;
new_options_label:=:NEW.options_label;
--new_option_mapping:=:NEW.options_mapping; --TODO: add this feature later
new_option_value:=:NEW.option_value;
update metadata set
xml_string=(UPDATEXML(XMLTYPE(xml_string),
'/metadata/fields/field[@name=''' || field_name || ''']/option[@value=''' || new_option_value || ''']/text()',
new_options_label)).getclobval() --must convert to clob as it's stored in the database that way
WHERE
id =(select metadata_id from spaces where prefix_code = space_prefix_code);
DBMS_OUTPUT.put_line(CHR(9) || TO_CHAR(SQL%ROWCOUNT)||' rows updated');
END;
/