Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Сравнение СУБД Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 .. 8 9 10 11 12 [13] 14 15 16 17   вперед  Ctrl
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
vadiminfo
Member

Откуда: Обнинск
Сообщений: 4802
SergSuper

Может еще кто напишет примеры для других СУБД

Оракл не рекомендует рекурсий в триггерах, т.е. на DML delete, чтобы и в триггере DML delete для той же таблы по причине резкого расхода памяти.

Конечно, можно, например, такое написать:

create or replace trigger ttt
AFTER DELETE
ON tree
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
DELETE FROM tree WHERE parent = :OLD.id;
COMMIT;
END;

Но недостатком будет, наприер, то, что в случае отката операции:
delete from tree where id = 1
все потомки id = 1 будут удалены, а сам этот узел останется. Это не подойдет для ограничений целостности.
28 окт 04, 01:03    [1066697]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
ASCRUS
Member

Откуда: МО Электросталь
Сообщений: 5994
автор
Но недостатком будет, наприер, то, что в случае отката операции:
delete from tree where id = 1
все потомки id = 1 будут удалены, а сам этот узел останется. Это не подойдет для ограничений целостности.

Отсюда поподробнее пожалуйста. Получаются, что изменения внутри триггера не попадают в проводимую транзакцию и коммитяться отдельно ? Я так понимаю это из за обьявленной "PRAGMA AUTONOMOUS_TRANSACTION" ? А чем Вы руководствовались, обьявляя отдельную транзакцию в триггере, почему нельзя изменения внутри него провести в пределах основной транзакции ?
28 окт 04, 12:44    [1067932]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 67463
Блог
Лох Позорный
Я опять начинаю терять веру в человеков. С какой стати оракл решил чего то там мне наэкономить? Кто его об этом просил?

Затрудняюсь ответить - меня при этом не присутствовало.

Лох Позорный
А если мне понадобится использовать условие Is Null на индексированное уникальное необязательное поле, что, индексом уже никак не получится воспользоваться?

Вообще-то получится. Другой вопрос, что не припомню, чтобы мне это требовалось.

Лох Позорный
В аксесе, например, включение/невключение Null'ов в индекс - задается в св-вах индекса. Что в общем-то и логично.

Безусловно, с точки зрения продвинутого специалиста, чем больше настроек - тем лучше. Но, честно говоря, в общем случае "оракл с мелкими недостатками" я предпочту "акцессу с мелкими преимуществами" :)
28 окт 04, 13:08    [1068055]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 67463
Блог
vadiminfo

В Оракле тоже есть иерархические запросы. Например, чтобы удалить узел id = 1 со всеми потомками из примера, который привел SergSuper можно выполнить DML

Возможно, туда нужно еще добавить что-то типа order by level desc - иначе если constraint не deferred, будет ошибка удаления родительской записи.
28 окт 04, 13:13    [1068088]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
protector
Member

Откуда: Иваново, Россия
Сообщений: 600
ASCRUS
Отсюда поподробнее пожалуйста. Получаются, что изменения внутри триггера не попадают в проводимую транзакцию и коммитяться отдельно ? Я так понимаю это из за обьявленной "PRAGMA AUTONOMOUS_TRANSACTION" ? А чем Вы руководствовались, обьявляя отдельную транзакцию в триггере, почему нельзя изменения внутри него провести в пределах основной транзакции ?


А потомучто в ORACLE нельзя в тригерх for Each Row обращаться к той же таблице, которая вызвала тригер в рамках той же транзакции.

PS: Автономные транзакции это такй костыль, при помощи которого Оракул решает проблемы кривизны собственного ядра, растущие ещё из глубины веков. Делать автономные транзакции в тригерах дурдом. Это нужно только в некоторых особых случаях, да и то разработчик должен понимать что к зачем ему это надо. А может и не надо.
28 окт 04, 16:30    [1069204]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 67463
Блог
protector
А потомучто в ORACLE нельзя в тригерх for Each Row обращаться к той же таблице, которая вызвала тригер в рамках той же транзакции.

PS: Автономные транзакции это такй костыль, при помощи которого Оракул решает проблемы кривизны собственного ядра

В данном случае, похоже, Вы говорите по принципу "слышал звон".
28 окт 04, 18:25    [1069725]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
Pi
Member

Откуда:
Сообщений: 278
SergSuper
Pi
считаю это отличие маленьким, поскольку создать таблицу типа ТаЖеСамаяТаблица_Лог + оператор Insert в теле триггера - это детская забава по сравнению с написанием бизнес-кода + его отладкой + его тестированием + его сдачей + его переопределением + его перепиской +...+...

Ну тогда можно сказать что и между Ораклом и МС СКЛ различий почти нет :)

А вообще чем кидаться красивыми умными словами давайте посмотрим как триггеры будут выглядеть на разных СУБД.

Вот например триггер на удаления дерева c подветками для MS SQL (предполагается что стоит рекурсивный вызов триггеров)

create table tree(id int identity, parent int null, caption varchar(55))

go

create trigger ttt om tree for delete as
begin
if not exists(select * from deleted) return
delete t
  from tree t, deleted d
  where d.id=t.parent
end
Может еще кто напишет примеры для других СУБД, для других задач? Главное чтоб были короткие и понятные.


Начну с Oracle. Дабы не смущать публику и себя исходными данными, я взял пример, поставляемый вместе с MS SQL Server 2000, точнее - это "Microsoft Analysis Services Samples", foodmart 2000.mdb.

Оттуда выбрана таблица "employee", как имеющая подходящие свойства:
Pi
SELECT LEVEL, T.* FROM "employee" T
CONNECT BY PRIOR EMPLOYEE_ID=SUPERVISOR_ID
START WITH EMPLOYEE_ID = 1

MaxLevel Q-ty of rows
---------- ------------
7 1155

за 1,623 сек. я узнал, что в таблице 1155 записей максимально 7-го уровня подчинения (начальный - 1).

Далее отрабатываю скрипт:
DROP TABLE "EMP_LOG";
DROP TABLE "EMP";
CREATE TABLE EMP AS SELECT * FROM "employee";
CREATE TABLE "EMP_LOG" AS SELECT * FROM EMP  WHERE 0=1;
CREATE OR REPLACE TRIGGER EMP_BEFORE_TR AFTER DELETE ON EMP FOR EACH ROW
BEGIN
  INSERT INTO EMP_LOG ("EMPLOYEE_ID") VALUES (:OLD.EMPLOYEE_ID); END;
/
CREATE OR REPLACE TRIGGER EMP_HIERA_TR AFTER DELETE ON EMP
BEGIN
  INSERT INTO EMP_LOG (EMPLOYEE_ID)    SELECT T.EMPLOYEE_ID FROM EMP T     CONNECT BY PRIOR EMPLOYEE_ID=SUPERVISOR_ID
     START WITH EMPLOYEE_ID IN (SELECT EMPLOYEE_ID FROM EMP_LOG);
  DELETE FROM EMP_LOG; END; 
/
Да, не так красиво, как у SergSuper!
Имеем два триггера вместо одного, и еще создали доп. таблицу! Может, можно и лучше - ведь я так делал еще в 1998 году на 7-й версии Oracle, - ну, да что уж поделать, уж как пришло в голову.

Запускаем удаление:
Pi
delete from emp t where EMPLOYEE_ID = 1

и - через 0,03 сек. все записи из таблицы emp удалены (поскольку я задал Самого Большого БОССА).

Ну, а теперь - к дружищу MS SQL.
DROP TABLE emp;
GO
SELECT * INTO emp FROM employee;
GO
CREATE TRIGGER emp_hiera_tr om emp FOR DELETE AS BEGIN
IF NOT EXISTS(SELECT * FROM deleted)RETURN
DELETE EMP 
  FROM emp T, deleted D
  WHERE T.employee_id = D.supervisor_id
END
GO
exec sp_dboption 'Orcl64','recursive triggers','true'
GO 
Собственно, код взят у SergSuper.

Пробуем - и неудача!
MS SQL
Server: Msg 170, Level 15, State 1, Procedure emp_hiera_tr, Line 1
Line 1: Incorrect syntax near 'om'.

Смотрим... ага! меняем
CREATE TRIGGER emp_hiera_tr om emp FOR DELETE AS BEGIN на
CREATE TRIGGER emp_hiera_tr ON emp FOR DELETE AS BEGIN

Теперь вроде вусе путем!
Запускаем:
delete from emp where EMPLOYEE_ID = 1;
MS SQL
(1 row(s) affected)

В самом деле? Одну запись? Проверяем... Да, так и есть! Удалена только одна запись. тогда меняем триггер:
DROP TRIGGER emp_hiera_tr 
GO
CREATE TRIGGER emp_hiera_tr ON emp FOR DELETE AS BEGIN
DELETE EMP 
  FROM emp T, deleted D
  WHERE T.employee_id = D.supervisor_id
END
GO
И - запускаем команду
[SRC]delete from emp where EMPLOYEE_ID = 1;[src]
MS SQLServer
Msg 217, Level 16, State 1, Procedure emp_hiera_tr, Line 2
Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).


Вот тебе, бабушка, и Юрьев день!

Лезем в документацию:
MS SQLServer
Using Nested Triggers
...Triggers can be nested up to 32 levels...


Да, так и должно было быть!

Ну, господа эксперты еще выскажутся,
а я подведу первичные итоги:


1. Приведенный пример в Oracle выглядит сложнее. Правда, я лично его написал не думая, по памяти, а MS SQL взял готовый - но это уже издержки образования.

2. Пример в Oracle работает очень быстро. Скажем, удаление из аналогичной таблицы (БЕЗ триггера!) командой delete from emp1 дает... те же 0,3 сек.

3. Пример в MS SQL, ВООБЩЕ ГОВОРЯ, НЕ РАБОТОСПОСОБЕН. Этот тот самый геморрой, о котором я имел место говорить.

4. Попутно желающие могут увидеть, что Oracle поддерживает очень интересную форму запроса - иерархическую:
Pi
select max(level) "MaxLevel", count(*) "Q-ty of rows" from "employee" t
connect by prior EMPLOYEE_ID=SUPERVISOR_ID start with EMPLOYEE_ID = 1;

благодаря которой можно не только построить дерево (как подчиненных, так и боссов), но и узнать уровень иерархии. Подчеркну, что этот пример взят мною из Oracle 7.3 - уже там это все работало. Может, работало и раньше, но раньше я просто не работал :)

Поэтому прошу господ, ратующих за простоту (особенно гг. "аксесников"), вспоминать время от времени старую русскую поговорку -
Простота хуже воровства

Заранее благодарен всем за все конструктивные замечания и пожелания по форме и содержанию поста!
Засим - всего доброго!
Pi
P.S.
Примеры проверялись на
Athlon (Barton) 2500+, 1 Gb ОЗУ PC-2700, Windows 2003 EE (Windows NT 5.2 3790), MS SQL 2000 EE (8.00.760 (SP3)), Oracle 8.1.7.1.4
28 окт 04, 19:18    [1069889]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
Pi
Member

Откуда:
Сообщений: 278
protector
ASCRUS
Отсюда поподробнее пожалуйста. Получаются, что изменения внутри триггера не попадают в проводимую транзакцию и коммитяться отдельно ? Я так понимаю это из за обьявленной "PRAGMA AUTONOMOUS_TRANSACTION" ? А чем Вы руководствовались, обьявляя отдельную транзакцию в триггере, почему нельзя изменения внутри него провести в пределах основной транзакции ?


А потомучто в ORACLE нельзя в тригерх for Each Row обращаться к той же таблице, которая вызвала тригер в рамках той же транзакции.

PS: Автономные транзакции это такй костыль, при помощи которого Оракул решает проблемы кривизны собственного ядра, растущие ещё из глубины веков. Делать автономные транзакции в тригерах дурдом. Это нужно только в некоторых особых случаях, да и то разработчик должен понимать что к зачем ему это надо. А может и не надо.


Примерно так думали индейцы, глядя на мушкеты европейцев. Им, индейцам, европейские мушкеты казались костылями, на которые хиляки бледнолицые опирали свои собственные кривые ядр.. тьфу, тела. Им, индейцам, эти костыли вообще не нужны были! ;)

Приведу такой простой пример из некоторых особых случаях - Вы хотите, чтобы логгировались все изменения в базе, в том числе те, которые были незафиксированы. Т.е., транзакция откатилась, а в логе все, что Вы пожели, осталось. Автономные транзакции это решают очень просто.

На самом деле автономные транзакции - это просто другая парадигма, которую не все способны сразу оценить. Вот в Советском Союзе одна из крупнейших коммерческих систем была система Экспресс, которая продавала билеты. Так вот, из-за советской мировозрения эта система могла с точностью до 1 ответить на вопрос - сколько билетов продала Московская ж.д. за такой-то день. Но она никогда бы не смогла ничего вразумительного сказать - а сколько билетов она НЕ продала, сколько пассажиров остались за этот же неудовлетворенными. И добавление такой возможности было одним из первых в списке требований к созданию Экспресс-УЗ. Что же раньше не надо было? ДА! Раньше было не надо, поскольку это было советское хозяйство ...
28 окт 04, 19:34    [1069901]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
Pi
Member

Откуда:
Сообщений: 278
ASCRUS
автор
Но недостатком будет, наприер, то, что в случае отката операции:
delete from tree where id = 1
все потомки id = 1 будут удалены, а сам этот узел останется. Это не подойдет для ограничений целостности.

Отсюда поподробнее пожалуйста. Получаются, что изменения внутри триггера не попадают в проводимую транзакцию и коммитяться отдельно ? Я так понимаю это из за обьявленной "PRAGMA AUTONOMOUS_TRANSACTION" ? А чем Вы руководствовались, обьявляя отдельную транзакцию в триггере, почему нельзя изменения внутри него провести в пределах основной транзакции ?


Дело в том, г. ASCRUS, что разработчики Oracle, создавая свою базу еще в те времена, когда ВСЯ компьютерная мощь Соединенных Штатов была сравнима с десятком современных персоналок, обращали внимание в первую очередь на быстродействие. И они заметили, что транзакции можно разделить на "длинные" и "короткие". И если точно знать, что транзакция будет "короткой", то можно кое-что съэкономить. И прямо дали такую возможность разработчикам:
Application developers can improve the performance of short, nondistributed transactions by using the BEGIN_DISCRETE_TRANSACTION procedure
Поколебавшись (а может, и без колебаний) этот же механизм был использован для триггеров Row Level. Собственно, это решение и повлекло некоторые ограничения. почему в данном случае разработчики выбрали между вседозволенностью и скоростью второе - понятно (см. выше)

Возможно, сегодня и можно было бы изменить, да на свет уже появился MS SQL, который опытными разработчиками Digital ведется как раз в сторону вседозволенности - так зачем? кому надо, тот MS SQL купит...
28 окт 04, 19:52    [1069927]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
vadiminfo
Member

Откуда: Обнинск
Сообщений: 4802
ASCRUS

Отсюда поподробнее пожалуйста. Получаются, что изменения внутри триггера не попадают в проводимую транзакцию и коммитяться отдельно ? Я так понимаю это из за обьявленной "PRAGMA AUTONOMOUS_TRANSACTION" ? А чем Вы руководствовались, обьявляя отдельную транзакцию в триггере, почему нельзя изменения внутри него провести в пределах основной транзакции ?

Не только внутри триггера. Автономные транзакции позволяют изолировать DML-инструкции выполняемые в анонимном блоке, процедуре, функции, триггере, пакетной процедуре и пакетной функции от контекста транзакции вызывающего кода. Этот блок определяется как независимая транзакция, начатая другой транзакцией, которая является главной. Т.е. эти транзакции выполняют фиксацию или откат самомстоятельно. В моем примере прописана фиксация. Главная может откатить, а автономные уже зафиксировали результат.
Да, объявляется с помощью "PRAGMA AUTONOMOUS_TRANSACTION".
Руководствуюсь тем, что триггер на уровне записи, объявленный как автономная транзакция может читать из таблы, а обычный нет. Потому что в результате такого чтения могут получаться разные результаты при выполнении одной и той же DML и результат работы триггера может оказаться разным в зависимости, например, от порядка строк, который будет возвращен.
Но это просто пример. В общем случае он не подходит. Например, для реализации каскадного удаления для деревьев, поскольку должно быть удалено все или ничего.
Продолжаю считать, что рекурсия в триггерах не лучшее из лучшего. (Вообще рекурсия наверное хорошо для деуларативных языков, но не для процедурных IXMO). Хоть автономная транзакция хоть нет. И Оракл этого строго не рекомендует, равно как писать триггера по любому поводу. Тем более все что можно решить декларативно, должно быть решено декларативно.
Хотя другая правда в том, что тот же Оракл в случае применения Мультимастер репликации рекомендует декларативное каскадное удаление заменить соответствующим триггером.
Надеюсь, что в следующих версиях будет лучше.
Автономные транзакций позволяет в Оракле, например:
реализовывать протоколы об ошибках, хотя главная транзакция и откатится, счетчики неудачных попыток, фиксацию и откат в триггерах БД.
Про другие СУБД не знаю. Но интересуюсь.
28 окт 04, 20:09    [1069945]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
Pi
Member

Откуда:
Сообщений: 278
В приведенном мною выше коде есть существенная ошибка - триггер EMP_HIERA_TR был приведен не полностью. Полная версия такова:

CREATE OR REPLACE TRIGGER EMP_HIERA_TR 
AFTER DELETE ON EMP
BEGIN

  INSERT INTO EMP_LOG (EMPLOYEE_ID)    
    SELECT T.EMPLOYEE_ID FROM EMP T     
      CONNECT BY PRIOR EMPLOYEE_ID=SUPERVISOR_ID
      START WITH EMPLOYEE_ID IN (SELECT EMPLOYEE_ID FROM EMP_LOG);

    DELETE FROM EMP
      WHERE EMPLOYEE_ID IN (SELECT EMPLOYEE_ID FROM EMP_LOG) ; 

    DELETE FROM EMP_LOG; 
  END; 
/

Кроме того, в Oracle рекурсия тоже вызывает затык. Т.е. приведенный мною пример ВООБЩЕ ГОВОРЯ не работоспособен.

Уровень рекурсии для ORacle 8.1.7.4 - 50 вложенных вызовов.

Извините за ошибки!
Pi
28 окт 04, 20:50    [1069992]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
ASCRUS
Member

Откуда: МО Электросталь
Сообщений: 5994
Ну раз пошла такая пьянка, приведу и я для ASA триггер (хотя и на CASCADE DELETE все прекрасно работает).

Для начала отключим каскад:
ALTER TABLE "DBA"."ProductGroup" 
  ADD FOREIGN KEY "ProductGroup" ( "Parent_id" ) 
    REFERENCES "DBA"."ProductGroup" ( "ProductGroup_id" ) CHECK ON COMMIT;
Если бы здесь не стоял CHECK ON COMMIT, до AFTER триггера дело бы и не дошло и при удалении родительских нод мы бы получили ошибку. А так все ok - только на COMMIT ASA проверит ссылочную целостность, так что во время транзакции делаем с деревом что хотим.

Теперь приведенный пример под MSSQL прекрасно отработает, так как никаких ограничений на уровень вложенностей вызовов в ASA нет - все ограничивается только доступнами ресурсами. Однако пример с точки зрения ASA неуклюжий, поэтому напишем свой триггер, без всяких рекурсий:
CREATE TRIGGER ProductGroup_DeleteChild AFTER DELETE
ORDER 1 ON ProductGroup
REFERENCING OLD AS ParentsDeleted
FOR EACH STATEMENT
WHEN (
  // Отрубаем рекурсию
  VarExists('_IsCascadeDeny') = 0
)
BEGIN
  // Обьявляем быструю времянку для удаляемых нодов
  DECLARE LOCAL TEMPORARY TABLE Nodes (
    ProductGroup_id varchar(8) NOT NULL PRIMARY KEY
  ) NOT TRANSACTIONAL;

  // Обьявляем глобальную переменную, отрубающую рекурсию
  CREATE VARIABLE _IsCascadeDeny bit;

  // Получаем дочерние ноды через рекурсивный запрос
  INSERT INTO Nodes
    WITH RECURSIVE h (Parent_id, Node_id) AS (
      SELECT Parent_id, ProductGroup_id
      FROM ProductGroup
      WHERE Parent_id IN (
              SELECT ProductGroup_id
              FROM ParentsDeleted )
      UNION ALL
      SELECT g.Parent_id, g.ProductGroup_id
      FROM ProductGroup g
        INNER JOIN h ON h.Node_id = g.Parent_id )
    SELECT Node_id
    FROM h;

  // Удаляем дочерние ноды
  DELETE FROM ProductGroup
  WHERE ProductGroup_id IN (
    SELECT ProductGroup_id
    FROM Nodes );

  // Удаляем глобальную переменную
  DROP VARIABLE _IsCascadeDeny;

// Обработка ошибок в теле триггера
EXCEPTION
  WHEN OTHERS THEN
    // Удаляем глобальную переменную
    DROP VARIABLE _IsCascadeDeny;

    // Поднимаем обратно ошибку
    RESIGNAL;
END;
Что мы с него видим:
1. Он сделан как FOR EACH STATEMENT и будет вызываться только один раз для всего множества удаляемых нодов с дерева.
2. В ASA поддерживаются глобальные сессионные переменные
3. В ASA нет опций запрета вызова рекурсий, все это можно разрулить через глобальные переменные
4. В ASA есть времянки, которые не участвуют в транзакциях, что соотвествующе прибавляем им скорости работы.
5. В ASA есть рекурсивные запросы, которые можно применять в SELECT и INSERT, но не в DELETE. Соотвествующе поэтому и была создана времянка.
6. В ASA есть понятие исключений для блоков BEGIN..END и соотвествующая обработка их.

В итоге при
DELETE FROM ProductGroup
WHERE ProductGroup_id IN ('Прод', 'Тех');
будет один раз вызван написанный выше триггер, который удалит все нужные дочерние ноды. Однако SELECT @@ROWCOUNT возвратит 2 записи, так как в ASA эта системные глобальные переменные имеют свою область видимости (что особенно приятно для @@IDENTITY).

В дополнение - мне лично WITH RECURSIVE, использующийся для обработки деревьев в ASA и DB2 нравиться больше, чем Ораклевый вариант. Вместо обьяснений приведу пример почему:
WITH RECURSIVE h (Parent_id, Node_id, Level, Path) AS (
  SELECT Parent_id, ProductGroup_id, 0, ProductGroup_id
  FROM ProductGroup
  WHERE Parent_id IS NULL
  UNION ALL
  SELECT g.Parent_id, g.ProductGroup_id, h.Level + 1, h.Path || '/' || g.ProductGroup_id
  FROM ProductGroup g
    INNER JOIN h ON h.Node_id = g.Parent_id )
SELECT Replicate('-', Level * 4) || Name AS Name, h.*
FROM h
  INNER JOIN ProductGroup pg ON pg.ProductGroup_id = h.Node_id
ORDER BY Path;
А это результат:
NameParent_idNode_idLevelPath
'Продукты питания''Прод'0'Прод'
'----Молочные продукты''Прод''Молоч'1'Прод/Молоч'
'----Хлебобулочные изделия''Прод''Хлеб'1'Прод/Хлеб'
'Техника''Тех'0'Тех'
'----Бытовая техника''Тех''БытТех'1'Тех/БытТех'
'----Видеоэлектронника''Тех''ВидеоТех'1'Тех/ВидеоТех'
'--------Видеомагнитофоны''ВидеоТех''ВМ'2'Тех/ВидеоТех/ВМ'
'--------Телевизоры''ВидеоТех''ТВ'2'Тех/ВидеоТех/ТВ'

Из за того, что в рекурсивном запросе можно отдельно указать запрос, откуда брать родителей и запрос, откуда брать детей, можно:
1. Строить рекурсивные запросы по деревьям, хранящимся во множестве таблиц
2. Организовывать нарастающие переменные, в данном случае были организованы переменные Level (уровень вложености нода), которая использовалась для отступа в наименовании группы и Path (путь к ноду), по которой была произведена сортировка нодов относительно каждого родительского нода.
Насколько я понимаю, чтобы все это проделать в Оракле одним чистым запросом отделаться нельзя будет.

P.S. Красивее было бы конечно в наименовании отступы ставить пробелами, но у Judge тэг CSV их кушает дюже хорошо :)
29 окт 04, 06:50    [1070189]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
protector
Member

Откуда: Иваново, Россия
Сообщений: 600
[quote Pi]Примерно так думали индейцы, глядя на мушкеты европейцев. Им,
индейцам, европейские мушкеты казались костылями, на которые хиляки
бледнолицые опирали свои собственные кривые ядр.. тьфу, тела. Им, индейцам,
эти костыли вообще не нужны были! ;)[/quote]
Очень красочный пример :) Только они зачастую и вправду не нужны. Во многих
серверах нет автономных транзакций и люди прекрасно без этого обходятся.

[quote Pi]Приведу такой простой пример из некоторых особых случаях - Вы
хотите, чтобы логгировались все изменения в базе, в том числе те, которые
были незафиксированы. Т.е., транзакция откатилась, а в логе все, что Вы
пожели, осталось. Автономные транзакции это решают очень просто.[/quote]
Да спору нет. Решают они это очень просто. Но опять-же повторюсь, что в
других серверах это тоже решается, по другому, иногда не так просто, но
решается. Вы лучше про минусы автономных транзакций раскажите, про плюсы
своего любимого сервера все горазды говорить, про минусы обычно же
умалчивают.

[quote Pi]На самом деле автономные транзакции - это просто другая парадигма,
которую не все способны сразу оценить.[/quote]
Видать не судьба. Ну не могу я её оценить и всё тут. Она прямо нарушает ACID
вот и всё, что тут ещё скажешь.
[quote Pi]Вот в Советском Союзе одна из крупнейших коммерческих систем была
система Экспресс, которая продавала билеты. Так вот, из-за советской
мировозрения эта система могла с точностью до 1 ответить на вопрос - сколько
билетов продала Московская ж.д. за такой-то день. Но она никогда бы не
смогла ничего вразумительного сказать - а сколько билетов она НЕ продала,
сколько пассажиров остались за этот же неудовлетворенными. И добавление
такой возможности было одним из первых в списке требований к созданию
Экспресс-УЗ. Что же раньше не надо было? ДА! Раньше было не надо, поскольку
это было советское хозяйство ...[/quote]
И к чему бы это?

Posted via ActualForum NNTP Server 1.1

29 окт 04, 11:04    [1070601]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
protector
Member

Откуда: Иваново, Россия
Сообщений: 600

[quote softwarer][quote protector]
А потомучто в ORACLE нельзя в тригерх for Each Row обращаться к той же таблице, которая вызвала тригер в рамках той же транзакции.

PS: Автономные транзакции это такй костыль, при помощи которого Оракул решает проблемы кривизны собственного ядра

В данном случае, похоже, Вы говорите по принципу "слышал звон".[quote]
Это какой же такой звон я слышу? Может укажете мне сирому... Не дадите умереть в неведение...

Posted via ActualForum NNTP Server 1.1

29 окт 04, 11:08    [1070610]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
protector
Member

Откуда: Иваново, Россия
Сообщений: 600

[quote ASCRUS][/quote]
Здорово. Всё больше убеждаюсь, что в АSA самый лучший SQL на сегодняшний день. Оракулу не чета.

Posted via ActualForum NNTP Server 1.1

29 окт 04, 11:33    [1070726]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
vadiminfo
Member

Откуда: Обнинск
Сообщений: 4802
protector

Во многих
серверах нет автономных транзакций и люди прекрасно без этого обходятся.

Так люди прекрасно обходились и без компьтеров, телевизоров и т.д. в позопрошлом веке. И вред от них тоже есть. Т.е. довод основанный на том, что люди прекрасно обходятся, не может быть безупречным во всех отношениях и нуждается в уточнених. Мы как раз здесь и пытаемся уточнять.
Мне, например, интересны все сведения, поскольку меня интересуют технолгоии БД вообще и СУБД, в частности. Хотя я Ораклист, и это не может не влиять на желание, чтобы он был лучшим, как бы я ни старался быть объективным.
29 окт 04, 12:48    [1071027]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 67463
Блог
ASCRUS
Ну раз пошла такая пьянка, приведу и я для ASA триггер

Ну раз пошла такая пьянка, приведу и для Oracle. Правда - на скорую руку, так что проверил работоспособность, но не уверен в оптимальности.

create table parented (
  id integer not null primary key, 
  parent_id integer constraint parent_fk references parented (id) 
    initially deferred deferrable) ;
insert into parented values (0, null) ;
insert into parented select rownum, rownum - 1 from dba_objects where rownum <= 100 ;

create or replace package parented_deleting is
  id integer ;
  into_cascade boolean := false ;
end ;
/

create or replace trigger ad_parented_cascade_s
  after delete on parented
declare
  type TRecords is table of parented.id%type ;
  records TRecords ;
begin
  if parented_deleting.into_cascade then return ; end if ;
  parented_deleting.into_cascade := true ;
  select id bulk collect into records from parented 
    start with parent_id = parented_deleting.id 
    connect by prior id = parent_id
    order by level desc ;
  forall i in records.first..records.last
    delete from parented where id = records ( i ) ;
  parented_deleting.into_cascade := false ;
exception 
  when others then
    parented_deleting.into_cascade := false ;
    raise ;
end ;

create or replace trigger ad_parented_cascade_r
  after delete on parented
  for each row
begin
  parented_deleting.id := :old.id ;
end ;

delete from parented where id = 10 ;
29 окт 04, 13:32    [1071221]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
ASCRUS
Member

Откуда: МО Электросталь
Сообщений: 5994
Я думаю автономные транзакции (как и любое функциональное расширение) конечно же нужны и нельзя говорить на любую фичу, которая отстуствует в твоей СУБД - что это плохо или не нужно. Наоборот - это хорошо, при условии, что знаешь как это готовить. В принципе те примеры с event-ами, что раньше я приводил для ASA можно назвать синонимом таких автономных транзакций - так как события запускаются в параллейной сессии, то недолго написать событие, которому передается в качестве параметра строка запроса (или целый батч), которое событие выполняет через динамический SQL, шлепая следом COMMIT. Тогда в любом триггере достаточно написать на неудачный аудит:
TRIGGER EVENT event_DoSQL (@SQL = 'INSERT INTO Table ...');
и смело откатываться, событие "event_DoSQL" в данном случае будет запущено уже автономно в параллейной сессии и никоим образом не будет зависеть от жизни транзакций в вызывавшей его сессии. Сам текст события будет такой:
CREATE EVENT "event_DoSQL"
HANDLER
BEGIN 
  EXECUTE IMMEDIATE WITH RESULT SET OFF Event_Parameter('@SQL');
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    MESSAGE 'Ошибка выполнения динамического SQL:/n' || ErrorMsg() TO LOG;
    ROLLBACK;
END;
Фактически думаю очень похоже получается на Ораклевые автономные транзакции :)
29 окт 04, 13:41    [1071270]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
ASCRUS
Member

Откуда: МО Электросталь
Сообщений: 5994
softwarer
Ну раз пошла такая пьянка, приведу и для Oracle.

Ну вот и еще один человек, который умеет правильно готовить кошек :)

Думаю на instance триггерах можно и для MSSQL нормальное решение накатать без ограничений, так что пока мы в очередной раз пришли только к одному выводу - все можно реализовать на всем. Зависит это только от наших познаний и время разработки реализации поставленной задачи обратно пропорционально наличию подходящего штатного функционала в СУБД.
29 окт 04, 13:46    [1071285]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
Pi
Member

Откуда:
Сообщений: 278
vadiminfo
... Мы как раз здесь и пытаемся уточнять.
Мне, например, интересны все сведения, поскольку меня интересуют технолгоии БД вообще и СУБД, в частности. Хотя я Ораклист, и это не может не влиять на желание, чтобы он был лучшим, как бы я ни старался быть объективным.


Разделяю Вашу позицию. Сам я работал на R:base, DB2/OS2, DB2/400, Oracle, MS SQL, и не очень считаю себя субъективным, но опасность такая есть, поэтому и предлагаю здесь конкретные решения. Правда, иногда с ошибками :((

А что касается парадигм, то именно потому, что мне лично приходилось с DOS-а пересаживаться на OS/400, вязаться с базами на майнфреймах и UNIX-системах, именно поэтому я в первую очередь обращаю внимание на то, что разница в системах - это именно разные парадигмы. Впрочем, намного лучше это сказал еще Кузьма
Прутков
Многие вещи нам непонятны не потому, что наши понятия слабы, а потому, что они не входят в круг наших понятий

Прутков
Вещи бывают великими и малыми не токмо по воле судьбы и обстоятельств, но также по понятиям каждого
29 окт 04, 13:47    [1071293]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
protector
Member

Откуда: Иваново, Россия
Сообщений: 600

vadiminfo

protector


Во многих
серверах нет автономных транзакций и люди прекрасно без этого обходятся.


Так люди прекрасно обходились и без компьтеров, телевизоров и т.д. в позопрошлом веке. И вред от них тоже есть. Т.е. довод основанный на том, что люди прекрасно обходятся, не может быть безупречным во всех отношениях и нуждается в уточнених.
Мы как раз здесь и пытаемся уточнять.

Это то да. Есть такое мнение: "Фичи лишними не бывают". Возможно так оно и есть. Но только каждая фича, как уже здесь кто-то сказал, это динамит в руки обезьяне. При неграмотном использовании можно натворит такого что не разгребёшь. Тут надо сопоставить все плюсы и минусы. Хотя этот спор больше теоретический. Мне лично глубоко наплевать в каком сервере какие фичи есть. Что есть тем и будем пользоваться. Какая в сущности разница. Оракул Сибэйс или Информикс. Главное чтобы работало надёжно и быстро. А как это достигается мне не интересно.

vadiminfo

Мне, например, интересны все сведения, поскольку меня интересуют технолгоии БД вообще и СУБД, в частности. Хотя я Ораклист, и это не может не влиять на желание, чтобы он был лучшим, как бы я ни старался быть объективным.

Это хорошо :) Тут я полностью солидарен. Объективность это весчь. :)




Posted via ActualForum NNTP Server 1.1

29 окт 04, 13:49    [1071302]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 67463
Блог
ASCRUS
Фактически думаю очень похоже получается на Ораклевые автономные транзакции :)

В Оракле, возможно, к этому будет ближе понятие pipe - это механизм, которым процессы могут использовать для обмена сообщениями. Процессом-приемником и исполнителем в данном случае может выступать, например, job. Разница с автономной транзакцией в том, что автономная транзакция выполняется "в том же потоке", то есть основная ждет ее завершения, беспроблемно идет передача параметров в обоих направлениях, исключения автономной транзакции могут быть обработаны в основной. А event, я так полагаю, выполняется именно что параллельно.
29 окт 04, 14:05    [1071379]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 67463
Блог
ASCRUS
Ну вот и еще один человек, который умеет правильно готовить кошек :)

Меня тут поправил один уважаемый коллега - забыл упомянуть, что сэкономил несколько "технических" строк. Реально поле id нужно делать массивом, дабы правильно шли массовые удаления.
29 окт 04, 14:23    [1071480]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
Pi
Member

Откуда:
Сообщений: 278
"Возвращаясь к нашим баранам". Ниже приведен код, относящийся к иерархическому удалению записей таблицы триггерами:
DROP TABLE "EMP_TMP";
DROP TABLE "EMP";
CREATE TABLE EMP AS SELECT * FROM "employee";
CREATE GLOBAL TEMPORARY TABLE "EMP_TMP" AS SELECT * FROM EMP  WHERE 0=1;
CREATE OR REPLACE VIEW EMP_V AS
  SELECT EMP.* FROM EMP;
/  
CREATE OR REPLACE TRIGGER EMP_INSTEAD_TR 
INSTEAD OF DELETE ON EMP_V 
REFERENCING OLD AS OLD              -- new 
FOR EACH ROW
DECLARE
    empCount NUMBER;
BEGIN
  SELECT COUNT(*) INTO empCount 
      FROM emp e
      WHERE e.EMPLOYEE_ID = :OLD.EMPLOYEE_ID;

 IF empCount >= 1 THEN

  INSERT INTO EMP_TMP (EMPLOYEE_ID)    
    SELECT T.EMPLOYEE_ID FROM EMP T     
      CONNECT BY PRIOR EMPLOYEE_ID=SUPERVISOR_ID
        START WITH EMPLOYEE_ID = :OLD.EMPLOYEE_ID;
  
  DELETE FROM EMP
         WHERE EMPLOYEE_ID IN 
           (SELECT EMPLOYEE_ID FROM EMP_TMP);

  DELETE FROM EMP_TMP;               
 END IF;
END;
/

SQL> set timing on;
SQL> SELECT COUNT(*) FROM EMP;

COUNT(*)
----------
1155

Executed in 0,16 seconds

SQL> delete from emp_v t where EMPLOYEE_ID = 1;

1 row deleted

Executed in 1,983 seconds

SQL> SELECT COUNT(*) FROM EMP;

COUNT(*)
----------
0

Executed in 0,01 seconds
29 окт 04, 14:26    [1071489]     Ответить | Цитировать Сообщить модератору
 Re: А зачем нужен этот монстр....... MS SQL?  [new]
ASCRUS
Member

Откуда: МО Электросталь
Сообщений: 5994
Кстати все примеры неплохо в FAQ по каждой СУБД ложаться - все обьяснено, проверено и опробовано. Так что глядишь по ходу всяких обсуждений еще и FAQ пополним :)
29 окт 04, 14:28    [1071503]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 .. 8 9 10 11 12 [13] 14 15 16 17   вперед  Ctrl
Все форумы / Сравнение СУБД Ответить