М.б. и извращения, делать вычисления в SQL, но...
В общем, экспериментирую по цепочке точек (траектории) посчитать углы
поворота в каждой.
Осталось из VIEW с посчитанными углами перенести данные обратно в таблицу
точек.
И хочется это красиво, пересечением множеств :-)
Обе СУБД MS SQL и Firebird поддерживают обычный синтаксис оператора
UPDATE. СУБД MS SQL также поддерживает синтаксис оператора UPDATE,
в котором выполняется соединение (join) и производится обновление одной
из таблиц соединения. Можно думать об этом как об условии WHERE
на стероидах. Если такая функция очень нужна, то ее можно реализовать в
СУБД Firebird с использованием представлений (views).
Речь про
update table1
set table1.column1 = table2.column2
from table2 where .....
Написана в целом логичная вещь, за парой исключений.
Во первых VIEW вещь глобальная и напрваление "каждому запросу свою вьюху"
настораживает
Во-вторых, что, если источник данных - тоже VIEW с вычислениями?
Поскольку VIEW увы не умеет быть частично обновляемый (относительно одних
столбцов, но не других), то не проходит например
CREATE OR ALTER VIEW UPDATE_METRICS(
IDX, ANGLE, TURN)
AS
select t.idx, v.angle, t.turn
from metrics t, vector_angles_deg v where v.metrics_idx = t.idx
-----
update update_metrics set turn=angle
-----
Unsuccessful execution caused by system error that does not preclude
successful execution of subsequent statements.
Attempt to execute an unprepared dynamic SQL statement.
=========================
обвязывать VIEW триггерами не интересно - тогда проще процедуру или
execute block сделать.
с курсором, императивно.
но ведь не красиво перебирать курсором....
==========================
"Лобовое" update metrics set turn = (select angle from vector_angles_deg
where metrics_idx = idx)
тоже некрасиво, императивненько. Да и выдаёт 42 чтения VECTORS на 7
обновлённых строк в METRICS
PLAN JOIN (VECTOR_ANGLES_DEG VECTOR_ANGLES_RAD VECTOR_COSINES Q INDEX
(PK_VECTORS), VECTOR_ANGLES_DEG VECTOR_ANGLES_RAD VECTOR_COSINES P INDEX
(FK_VECTORS_1))
PLAN (METRICS NATURAL)
Приятный "декларативный" бонус - обновляются все точки, в том числе первая
и последняя, где никакuх углов нет: они заполняются NULL
===========================
execute block as
declare variable id integer;
declare variable an double precision;
begin
for select angle, metrics_idx from vector_angles_deg into :an, :id
do update metrics set turn = :an where idx = :id;
end;
Жуть некрасивая. Зато какой хороший план, всего 5+6 чтений на 5 обновлений.
Правда не заNULLяются остальные 2 строки metrics, придётся отдельно их
заранее чистить, без фильтрации или с неэффективной фильтрацией where not
exists.
Но всё-равно не n^2 !
PLAN (METRICS INDEX (PK_METRICS))
PLAN JOIN (VECTOR_ANGLES_DEG VECTOR_ANGLES_RAD VECTOR_COSINES P NATURAL,
VECTOR_ANGLES_DEG VECTOR_ANGLES_RAD VECTOR_COSINES Q INDEX (PK_VECTORS))
PS: С курсором не делал, но результат, думаю, будет идентичен.
==============
Хорошая штука UPDATE с JOIN'ом :-)
Ну и напоследок - с чем разлекался.
Данные:
insert into layers values (1, 1, null);
insert into objects values (1,1,1,1,1, null);
insert into metrics values (1, 0,3 ,1,null);
insert into metrics values (2, 0,0 ,1,null);
insert into metrics values (3, -4,0 ,1,null);
insert into metrics values (4, -5,1 ,1,null);
insert into metrics values (5, -6,1 ,1,null);
insert into metrics values (6, -7,1 ,1,null);
insert into metrics values (7, -6,1 ,1,null);
execute procedure make_vectors;
Cтруктура:
CREATE GLOBAL TEMPORARY TABLE LAYERS (
IDX INTEGER NOT NULL,
NUMBER INTEGER NOT NULL,
NAME VARCHAR(200)
) ON COMMIT DELETE ROWS;
CREATE GLOBAL TEMPORARY TABLE METRICS (
IDX INTEGER NOT NULL,
X INTEGER NOT NULL,
Y INTEGER NOT NULL,
OBJECT INTEGER NOT NULL,
TURN DOUBLE PRECISION
) ON COMMIT DELETE ROWS;
CREATE GLOBAL TEMPORARY TABLE OBJECTS (
IDX INTEGER NOT NULL,
LAYER SMALLINT NOT NULL,
OBJTYPE SMALLINT NOT NULL,
NUMBER SMALLINT NOT NULL,
CODE INTEGER NOT NULL,
SEMANTICS BLOB SUB_TYPE 1 SEGMENT SIZE 80
) ON COMMIT DELETE ROWS;
CREATE GLOBAL TEMPORARY TABLE VECTORS (
IDX INTEGER NOT NULL,
X INTEGER NOT NULL,
Y INTEGER NOT NULL,
OBJECT INTEGER NOT NULL,
LEN DOUBLE PRECISION NOT NULL
) ON COMMIT DELETE ROWS;
ALTER TABLE LAYERS ADD CONSTRAINT PK_LAYERS PRIMARY KEY (IDX);
ALTER TABLE METRICS ADD CONSTRAINT PK_METRICS PRIMARY KEY (IDX);
ALTER TABLE OBJECTS ADD CONSTRAINT PK_OBJECTS PRIMARY KEY (IDX);
ALTER TABLE VECTORS ADD CONSTRAINT PK_VECTORS PRIMARY KEY (IDX);
ALTER TABLE LAYERS ADD CONSTRAINT UQ_LAYERS_NUM UNIQUE (NUMBER);
ALTER TABLE OBJECTS ADD CONSTRAINT UQ_OBJECTS UNIQUE (NUMBER);
ALTER TABLE VECTORS ADD CONSTRAINT FK_VECTORS_1 FOREIGN KEY (OBJECT)
REFERENCES OBJECTS (NUMBER);
ALTER TABLE VECTORS ADD CONSTRAINT FK_VECTORS_2 FOREIGN KEY (IDX)
REFERENCES METRICS (IDX);
ALTER TABLE METRICS ADD CONSTRAINT FK_METRICS_1 FOREIGN KEY (OBJECT)
REFERENCES OBJECTS (NUMBER);
ALTER TABLE OBJECTS ADD CONSTRAINT FK_OBJECTS_1 FOREIGN KEY (LAYER)
REFERENCES LAYERS (NUMBER);
SET TERM ^ ;
CREATE OR ALTER TRIGGER CALC_VECTOR_LEN FOR VECTORS
ACTIVE BEFORE INSERT POSITION 0
AS
begin
NEW.LEN = SQRT(NEW.X*NEW.X + NEW.Y*NEW.Y);
end
^
SET TERM ; ^
/******************************************************************************/
/***
Views ***/
/******************************************************************************/
/* View: VECTOR_COSINES */
CREATE OR ALTER VIEW VECTOR_COSINES(
METRICS_IDX,
COSINE_VALUE)
AS
select q.idx,
(p.x*q.x + p.y*q.y) / (p.len * q.len) as CosValue
from vectors p, vectors q
where q.idx = p.idx+1 and q.object = p.object
;
/* View: VECTOR_ANGLES_RAD */
CREATE OR ALTER VIEW VECTOR_ANGLES_RAD(
METRICS_IDX,
ANGLE)
AS
select metrics_idx, acos(cosine_value)
from vector_cosines
;
/* View: VECTOR_ANGLES_DEG */
CREATE OR ALTER VIEW VECTOR_ANGLES_DEG(
METRICS_IDX,
ANGLE)
AS
select metrics_idx, angle*180/PI()
from vector_angles_rad
;
/* View: VECTOR_SCALAR_PRODUCTS */
CREATE OR ALTER VIEW VECTOR_SCALAR_PRODUCTS(
METRICS_IDX,
PRODUCT)
AS
select p.idx, p.x*q.x + p.y*q.y
from vectors p, vectors q
where q.idx = p.idx+1 and q.object = p.object
;
/******************************************************************************/
/*** Stored
Procedures ***/
/******************************************************************************/
SET TERM ^ ;
CREATE OR ALTER PROCEDURE MAKE_VECTORS
AS
begin
delete from vectors;
insert into vectors(idx, object, x, y)
select u.idx, u.object, u.x - v.x, u.y - v.y
from metrics u, metrics v
where v.idx = u.idx+1 and u.object = v.object;
end^
SET TERM ; ^
--
Написано в почтовом клиенте браузера Opera: http://www.opera.com/mail/