Внешние ключи такого рода удобно описывать используя XPath, дополнив его выражениями вида '@field/element'. Например, рациональное поле может ссылаться на xml-атрибут, содержащийся в текстовом поле другой таблицы.
create table a( a1 num, a2 string ); create table b( b1 num, b2 num references a(@a2/k/m/n/@n1) ); |
create table a ( a1 num, a2 num ); create table b ( b1 num, b2 string ); alter table b add foreign key (@b2/k/m/n/@n1) references a(a2); |
create table a ( a1 num, a2 string ); create table b ( b1 num, b2 string ); alter table b add foreign key (@b2/k/m/n/@n1) references a(@a2/p/q/r/@r1); |
В текстовое поле может быть вставлен не только xml-текст
insert into tab (fld) values ('<tag>...</tag>'); |
insert into tab (fld) select * from a.b.c; |
Сначала родительская таблица, затем дочерняя. Пусть предшествующим звеном дерева является родительская таблица (таблица "a"), а последующим - дочерняя (таблица "b"), ссылающаяся на первичный ключ родительской. Пусть в дочерней таблице существует несколько записей, ссылающихся на одну и ту же родительскую запись - это означает, что следующий уровень дерева содержит несколько элементов. Звено дерева, состоящее из нескольких записей дочерней таблицы, будем называть множеством (set). Для извлечения дерева перечисляем имена таблиц - сначала родительской, затем дочерней.
при условии следующего DDL | запрос на DML | запрос выполнен так | ||
create table a ( id num primary key, data float ); create table b ( id num primary key, ref num references a(id), data float ); create table c ( id num primary key, link num references b(id), data float ); insert into a values (1, 12.3); insert into b values (10, 1, 23.4); insert into b values (20, 1, 34.5); insert into b values (30, 1, 45.6); insert into c values (100,10,56.7); insert into c values (101,10,67.8); insert into c values (200,20,78.9); insert into c values (201,20,89.1); insert into c values (300,30,91.2); | insert into tab (fld) select * from a.b.c; |
insert into tab (fld) values (' <a id=1 data=12.3> <b id=10 data=23.4> <c id=100 data=56.7/> <c id=101 data=67.8/> </b> <b id=20 data=34.5> <c id=200 data=78.9/> <c id=201 data=89.1/> </b> <b id=30 data=45.6> <c id=200 data=91.2/> </b> </a> '); |
при условии следующего DDL | запрос на DML | запрос выполнен так | ||
create table a ( id num primary key, data float ); create table b ( id num primary key, ref1 num references a(id), ref2 num references a(id), data float ); create table c ( id num primary key, lnk1 num references b(id), lnk2 num references b(id), data float ); insert into a values (1, 12.3); insert into a values (2, 23.4); insert into b values (10, 1, 2, 34.5); insert into b values (20, 1, 2, 45.6); insert into b values (30, 1, 2, 56.7); insert into b values (40, 1, 2, 67.8); insert into c values (100,10,20,78.9); insert into c values (101,10,20,89.1); insert into c values (200,30,40,91.2); insert into c values (201,30,40,88.8); | insert into tab (fld) select * from a.b#ref1.c#lnk1; |
insert into tab (fld) values (' <a id=1 data=12.3> <b id=10 ref2=2 data=34.5> <c id=100 lnk2=20 data=78.9/> <c id=101 lnk2=20 data=89.1/> </b> <b id=30 ref2=2 data=56.7> <c id=200 lnk2=40 data=91.2/> <c id=201 lnk2=40 data=88.8/> </b> </a> '); |
Сначала дочерняя таблица, затем родительская. Пусть предшествующим звеном дерева является дочерняя таблица (таблица "a"), а последующим - родительская (таблица "b"). Звено дерева, состоящее из записи родительской таблицы, будем называть эстафета (relay-race). Для извлечения дерева перечисляем имена таблиц - сначала дочерней, затем родительской.
при условии следующего DDL | запрос на DML | запрос выполнен так | ||
create table a ( id num primary key, ref num references b(id), data float ); create table b ( id num primary key, link num references c(id), data float ); create table c ( id num primary key, data float ); insert into с values (100, 34.5); insert into b values (10, 100,23.4); insert into a values (1, 10, 12.3); | insert into tab (fld) select * from a.b.c; |
insert into tab (fld) values (' <a id=1 data=12.3> <b id=10 data=23.4> <c id=100 data=34.5/> </b> </a> '); |
при условии следующего DDL | запрос на DML | запрос выполнен так | ||
create table a ( id num primary key, ref1 num references b(id), ref2 num references b(id), data float ); create table b ( id num primary key, lnk1 num references c(id), lnk2 num references c(id), data float ); create table c ( id num primary key, data float ); insert into с values (201, 78.9); insert into с values (200, 67.8); insert into с values (101, 56.7); insert into с values (100, 45.6); insert into b values (20, 200,201,34.5); insert into b values (10, 100,101,23.4); insert into a values (1, 10, 20, 12.3); | insert into tab (fld) select * from a#ref1.b#lnk1.c; |
insert into tab (fld) values (' <a id=1 data=12.3> <b id=10 data=23.4> <c id=100 data=45.6/> </b> </a> '); |
Медвежье ухо - это конструкция, в которой родительской и дочерней является одна и та же таблица (внешний ключ ссылается на уникальное поле своей же таблицы). Несколько подряд идущих записей в медвежьем ухе всегда будем рассматривать как одно звено (этим звено отличается от табмента), и будем называть такое звено списком (list).
Множество или список отличаются только в рациональном представлении, в xml-виде они выглядят одинаково.
при условии следующего DDL | запрос на DML | запрос выполнен так | ||
create table a ( id num primary key, ref num references a(id), lnk num references b(id), data float ); create table b ( id num primary key, ref num references b(id), data float ); insert into b values (300,null,3.3); insert into b values (30, 300, 3.2); insert into b values (3, 30, 3.1); insert into b values (400,null,4.3); insert into b values (40, 400, 4.2); insert into b values (4, 40, 4.1); insert into b values (500,null,5.3); insert into b values (50, 500, 5.2); insert into b values (5, 50, 5.1); insert into a values (100,null,500,34.5); insert into a values (10, 100, 400,23.4); insert into a values (1, 10, 300,12.3); | insert into tab (fld) select * from a.b; |
insert into tab (fld) values (' <a id=1 data=12.3> <b id=3 data=3.1> <b id=30 data=3.2> <b id=300 data=3.3> </a> <a id=1 data=23.4> <b id=4 data=4.1> <b id=40 data=4.2> <b id=400 data=4.3> </a> <a id=1 data=34.5> <b id=5 data=5.1> <b id=50 data=5.2> <b id=500 data=5.3> </a> '); |
В свою очередь xml-элементы могут быть преобразованы в бинарный вид и записаны в одноименные таблицы (xml-аттрибуты записываются в одноименные поля), а все xml-дерево будет преобразовано в рациональное дерево, образованное записями, которые ссылаются друг на друга внешними ключами. Такая вставка данных осуществляется не в поле, а под таблицу, порождая суб-дерево. Поэтому название (числового) поля должно быть опущено, иначе произойдет попытка преобразования текстовой (xml) строки в числовой вид, и возникнет сообщение об ошибке.
insert into tab values ('<tag>...</tag>'); |
insert into tab select * from a.b.c; |
Успешность записи xml-текста в таблицы зависит от того, соответствует ли схема базы данных вводимому xml (при несоответствии некоторые xml-под-деревья игнорируются).
Если вложенная таблица двумя своими полями ссылается на две разные записи обрамляющей таблицы, то в открывающем теге вложенной таблицы после ее названия через знак "#" нужно указать название соответствующего поля обрамляющей таблицы.
Если обрамляющая таблица двумя своими полями ссылается на две разные записи вложенной таблицы, то в открывающем теге обрамляющей таблицы после ее названия через знак "#" нужно указать название соответствующего поля вложенной таблицы.
Таким образом таблица и ее ссылающееся поле указываются в одном открывающем теге. Такое указание поля в открывающем теге также будем называть детерминацией, determination (в браузере она тоже предусмотрена). Различные варианты детерминации рассмотрены в отдельном документе. В примерах ниже предполагается, что все первичные ключи снабжены последовательностями, значения из которых вводятся в эти ключи по умолчанию.
при условии следующего DDL | запрос на DML | запрос выполнен так | ||
create table a ( id num primary key, lnk num references tab, data float ); create table b ( id num primary key, ref num references a(id), data float ); | insert into tab values (' <a data=12.3> <b data=23.4> <b data=34.5> <b data=45.6> </a> '); |
insert into tab values (1); insert into a values (10, 1, 12.3); insert into b values (101,10,23.4); insert into b values (102,10,34.5); insert into b values (103,10,45.6); -- секция "b" является множеством |
||
create table a ( id num primary key, lnk num references tab, data float ); create table b ( id num primary key, ref1 num references a(id), ref2 num references a(id), data float ); | insert into tab values (' <a data=12.3> <b data=23.4> <b data=34.5> <b data=45.6> </a> '); |
insert into tab values (1); insert into a values (10, 1, 12.3); -- "b" не внесено, т.к. неопределенность -- не разрешена с помощью детерминации |
||
insert into tab values (' <a data=12.3> <b#ref1 data=23.4> <b#ref1 data=34.5> <b#ref1 data=45.6> </a> '); |
insert into tab values (1); insert into a values (10, 1, 12.3); insert into b values (101,10,null,23.4); insert into b values (102,10,null,34.5); insert into b values (103,10,null,45.6); |
|||
create table a ( id num primary key, lnk num references tab, ref num references b(id), data float ); create table b ( id num primary key, data float ); | insert into tab values (' <a data=12.3> <b data=23.4> </a> '); |
insert into tab values (1); insert into a values (10, 1,100,12.3); insert into b values (100, 23.4); -- секция "b" является эстафетой |
||
insert into tab values (' <a data=12.3> <b data=23.4> <b data=34.5> <b data=45.6> </a> '); |
insert into tab values (1); insert into a values (10, 1,null,12.3); -- ни один "b" не введен, т.к. схема базы данных -- не содержит ни множества, ни списка для них -- (внесение одного "b" могло бы ввести в заблуждение -- программиста, отлаживающего программу) |
|||
create table a ( id num primary key, lnk num references tab, ref1 num references b(id), ref2 num references b(id), data float ); create table b ( id num primary key, data float ); | insert into tab values (' <a data=12.3> <b data=23.4> </a> '); |
insert into tab values (1); insert into a values (10, 1,null,null,12.3); -- "b" не внесено, т.к. неопределенность -- не разрешена с помощью детерминации |
||
insert into tab values (' <a#ref1 data=12.3> <b data=23.4> </a> '); |
insert into tab values (1); insert into a values (10, 1,100,null,12.3); insert into b values (100, 23.4); |
|||
create table a ( id num primary key, lnk num references tab, ref num references b(id), data float ); create table b ( id num primary key, ref num references b(id), data float ); | insert into tab values (' <a data=12.3> <b data=23.4> <b data=34.5> <b data=45.6> </a> '); |
insert into tab values (1); insert into a values (10, 1,101, 12.3); insert into b values (101, 102, 23.4); insert into b values (102, 103, 34.5); insert into b values (103, null,45.6); -- секция "b" является списком |
Вставить данные можно не только под рациональную таблицу, но и под конкретный xml-элемент, находящийся в текстовом поле рациональной таблицы (внутрь этого xml-элемента), если указать его с помощью XPath.
insert into tab/@fld/k/m/n values ('<tag>...</tag>'); insert into tab/@fld/k/m/n select * from a.b.c; |
было (в поле 'fld' таблицы 'tab') | запрос на DML | стало (в поле 'fld' таблицы 'tab') | ||
<k> <m> <n> <p/> </n> </m> </k> | insert into tab/@fld/k/m/n values ('<tag>...</tag>'); |
<k> <m> <n> <p/> <tag>...</tag> </n> </m> </k> |
||
<k> <m> <n> <p/> </n> </m> </k> | insert into tab/@fld/k/m/n select * from a.b.c; |
<k> <m> <n> <p/> <a> <b> <c/> <c/> </b> <b> <c/> <c/> </b> </a> <a> <b> <c/> <c/> </b> <b> <c/> <c/> </b> </a> </n> </m> </k> |
Извлечь можно не только несколько связанных рациональных таблиц, но и часть xml-дерева, содержащегося в текстовом поле рациональной таблицы. Для этого нужно указать корень под-дерева с помощью XPath, а само под-дерево - с помощью XTree. Такую комбинацию XPath и XTree будем называть XLang.
insert into tabname (field) select * from tab/@fld/k/m/n/a.b.c; |
было (в поле 'field' таблицы 'tabname') | запрос на DML | стало (в поле 'field' таблицы 'tabname') | ||
| insert into tabname (field) select * from tab/@fld/k/m/n/a.b.c; |
<a> <b> <c/> <c/> </b> <b> <c/> <c/> </b> </a> <a> <b> <c/> <c/> </b> <b> <c/> <c/> </b> </a> |
Чтобы была возможность вставить xml-данные не под таблицу, а сами по себе, над-таблицу можно не указывать.
при условии следующего DDL | запрос на DML | запрос выполнен так | ||
create table a ( id num primary key, data float ); create table b ( id num primary key, ref num references a(id), data float ); | insert values (' <a data=12.3> <b data=23.4> <b data=34.5> <b data=45.6> </a> '); |
insert into a values (10, 12.3); insert into b values (101,10,23.4); insert into b values (102,10,34.5); insert into b values (103,10,45.6); |
||
insert select * from tab/@fld/k/m/n/a.b; |
Не вызывает затруднений изменение поля (рациональной таблицы)
update tab set fld=( select * from a.b.c ); update tab set fld=( select * from a.b#ref1.c#lnk1 ); update tab set fld=( select * from t/@field/k/m/n/a.b.c ); update tab set fld='<a>...</a>'; |
update tab set @fld/p/q/r/@r1=( select * from a.b.c ); update tab set @fld/p/q/r/@r1=( select * from a.b#ref1.c#lnk1 ); update tab set @fld/p/q/r/@r1=( select * from t/@field/k/m/n/a.b.c ); update tab set @fld/p/q/r/@r1='<a>...</a>'; |
update tab set @fld/p/q/@@=( select * from a.b.c ); update tab set @fld/p/q/@@=( select * from a.b#ref1.c#lnk1 ); update tab set @fld/p/q/@@=( select * from t/@field/k/m/n/a.b.c ); update tab set @fld/p/q/@@='<a>...</a>'; |
Добавляется возможность удалить конкретный xml-элемент (со всем его содержимым)
Предикаты должны создаваться также для xml-аттрибутов.
Полномочия должны выдаваться также на xml-элементы.
Триггеры должны создаваться также для xml-элементов.
В XTree вложенные табменты не извлекаеются, если они не указаны. Например, если 'a' имеет вложенный табмент 'm', то выражением 'a.b.c' он извлечен не будет.
Аналогично XPath, в XTree возможны конструкции вида 'a.b | k.c', 'a.b*.c', 'a.b+.c', 'a.b?.c', 'a.b[@b1].c', 'a.b[@b1=5].c', 'a.b[0].c', 'a.(b | k)[0].c' и т.д. Гарантируется, что всегда сначала будет обработано звено с меньшим уровнем иерархии, и только затем с большим (это распространяется и на одноименные табменты под знаком '*' или '+').
XPath имеет выражения вида 'a//b' - предлагаю ввести симметричную конструкцию 'a..b' в XTree, которая означает табмент 'a', табмент 'b' и любое количество табментов любого имени между ними.
Кроме того, предлагаю использовать знак '!' для обозначения уровня иерархии в квадратных скобках (т.е. 'tab[!=5]'). Например, в выражении 'a.b.c.d.e' табмент 'a' имеет 0-й, 'b' имеет 1-й, 'c' имеет 2-й, 'd' имеет 3-й, 'e' имеет 4-й уровень. Все элементы списка (табменты одной секции) имеют одно и то же значение уровня иерархии.