24.06.2011 13:49, Khorsun Vlad пишет:
>>>> EB вполне устраивает.
>>>    Он не будет рекурсивным.
>> Этому есть какие-то причины теоретического плана или технического?
>    Нет конечно, это мой каприз.
Мне казалось, что ЕБ ничем от сохранёнки не отличаются кроме наличия
имени. Если это так, тогда невозможность рекурсии решается просто
введением ключевого слова или иного механизма позволяющего вызвать себя.

Видимо я ошибался. Но до сих пор не понимаю причину нежелания делать
рекурсию в ЕБ.
Возможно это как-то связано с мониторингом или другими подобными
механизмами.
Поэтому и хочется узнать причины из первых рук.
Расскажи в общих чертах.

Да, вобщем-то можно просто ввести опциональное имя для ЕБ.
Тогда нет нужды в каком-то дополнительном ключевом слове. :)

>> По факту единственным универсальным инструментом для работы с деревьями
>> на сервере остаются рекурсивные сохранёнки. :(
>    Не вижу в этом ничего плохого. Ну и это утверждение ничем не доказано.
Вот я и пытаюсь это обосновать.

>> Про удаление мы вроде бы выяснили:
>> delete from ... where id in (with recursive...)
>> отвалится, если связь без каскадного удаления, т. к. невозможно задать
>> порядок удаления.
>    Нет, мы выяснили что есть for with recursive который позволяет не
> писать процедуру (А ЧЕМ ПЛОХО ПИСАТЬ ПРОЦЕДУРУ ???)и обойтись без
> несуществующего рекурсивного EB
Т. е. без применения PL-SQL не обойтись. Согласен.
Хотя на мой взгляд какой-то вариант delete был бы более ясныйм и простым
способом...

>    Порядок детей ? В этом обсуждении первый раз слышу об этом.
> В более широком стандартном синтаксисе *есть* возможность указать
> сортировку на каждом уровне рекурсии отдельно. Но что-то я пока не
> встречал более 2-3 просьб это реализовать...
Тут я не прав - уже выясняли что можно:
https://groups.google.com/group/ru-firebird/browse_thread/thread/71b83182b6151dfd/654c5e8ab2e62a52?hl=ru&lnk=gst&q=%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0+%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%B0#654c5e8ab2e62a52
Хотя ИМХО с работающей сортировкой внутри было бы проще/красивше. :)

>> Нельзя сделать поиск по путям.
>    Ты с кем разговариваешь ? Я тебя уже потерял :)
Это когда узел идентифицируется не его ID-ом а последовательностью
значений какого-то атрибута по уровням (как путь в файловой системе)

>> Опять же, такой запрос как посчитать количество дочек для каждого узла в
>> указанной ветке будет отставать по скорости примерно на степень от
>> прямой рекурсивной реализации (как O(n) от O(n^2) или больше).
>    Опять бездоказательное утверждение. И опять не вижу причин отказываться
> от процедур.
Для простейшего дерева выдать количество непосредственных детей
действительно проблем нет:
with recursive TREE as (
  select 1 as LEV, ID, from SYMPTOMS where PARENT_ID is null
  union all
  select t.LEV + 1, s.ID
  from SYMPTOMS s inner join TREE t on s.PARENT_ID = t.ID
)
select
  t.LEV, t.ID, t.PARENT_ID
  (select count(*) from SYMPTOMS s where s.PARENT_ID = t.ID)
from TREE t

Но вот подсчитать количество всех детей у меня не вышло. :(
Карячится что-то такое, но не работает:
with recursive
  TREE_C (ID, PARENT_ID, CHILD_CNT) as (
    -- Все листики детей не имеют
    select s.ID, s.PARENT_ID, 0
    from SYMPTOMS s left join SYMPTOMS sc on sc.PARENT_ID = s.ID
    where sc.ID is null
    union all
    -- выбираем ролдителей и считаем количество прямых детей + сумму их
детей
    select sp.ID, sp.PARENT_ID, count(*) + sum(tc.CHILD_CNT)
    from SYMPTOMS sp inner join TREE_C tc on tc.PARENT_ID = sp.ID
    group by 1, 2
  )
select
  t.ID, CHILD_CNT
from TREE_C t
Пишет ошибку
Recursive member of CTE 'TREE_C' has GROUP BY clause

при замене группировки и inner join на подзапросы тоже облом:
    -- выбираем родителей и считаем количество прямых детей + сумму их детей
    select sp.ID, sp.PARENT_ID, --count(*) + sum(tc.CHILD_CNT)
      (select count(*) + sum(tc.CHILD_CNT) from TREE_C tc where
tc.PARENT_ID = sp.ID)
    from SYMPTOMS sp
    where exists(select 1 from TREE_C tc where tc.PARENT_ID = sp.ID)
Алиас TREE_C нельзя применять в подзапросах:
Table unknown
TREE_C
At line 12, column 39

Кто предложит рабочий вариант подсчёта общего количества прямых и
непрямых детей для указанной ветки?

Дальше можно будет трудоёмкость посчитать. :)

>> Т. е. даже простые вычисления на дереве с использованием СТЕ
>> использовать не получится. :(
>    Вот несчатье-то... И ряды Фурье на SQL сложно считать...
И даже простейший парсер xml-я тоже. :)
А вот те же числа Фибоначчи считаются на ура.
Ну да вроде всё это к деревянным данным не относятся.

>> Так же нет возможности организовать копирование веток, их слияние - т.
>> е. модификацию дерева.
>    Опять без доказательства.
Тут у меня даже идеи нет с какой стороны подходить без явной рекурсии
или внешнего стека.
Может кто-нибудь предложит набросок идеи?

>> В сухом остатке получается, что СТЕ - это базовый, но очень ограниченный
>> механизм. Для нормальной работы придётся либо использовать сохранёнки на
>> каждый чих, либо проделывать все манипуляции на клиенте...
>    Ну, похоже это твой путь, раз ты другого не нашёл
>...
>> П. С. Ну а если бы механизм СТЕ развился, чтобы покрывать хотя бы часть
>> этих задач, было бы просто нереально круто! :)
>    А может ты просто не нашёл решения для части этих задач ?
Вот и спрашиваю, может ещё какие-то подходы есть которые я не увидел?
У меня не получается выразить с помощью СТЕ задачи требующие прохода
снизу вверх по дереву.

> PS Не удивлюсь, если ты окажешься фанатом новомодных лямбда ф-ций (чи как
> их там - когда тело ф-ции пишут в месте её вызова, без объявления) :-D
Ничего плохого в лямбдах не вижу. Когда их употребляют к месту они
способствуют увеличению понятности уменьшению кода. :)
Если применять не к месту - получится лапша.
Собственно как и любые другие возможности языков.
Используя те же исключения или наследование можно такую кучу лапши
организовать... Ж:-О

П. С.
Пробуя написать подсчёт детей породил такого вот монстрика.

with recursive
TREE (LEV, ID, PARENT_ID) as (
  select
    1 as LEV, s0.ID, s0.PARENT_ID
  from SYMPTOMS s0 where s0.PARENT_ID is null
  union all
  select
    t.LEV + 1, s1.ID, s1.PARENT_ID
  from SYMPTOMS s1 inner join TREE t on s1.PARENT_ID = t.ID
),
TREE_C (IDD, LEV, GRANDAD_ID, PARENT_ID) as (
  select
    s.ID, t.LEV, t.ID as GRANDAD_ID, t.PARENT_ID
  from SYMPTOMS s inner join TREE t on s.PARENT_ID = t.ID
  union all
  select
    sc.ID, tc.LEV, tc.GRANDAD_ID as GRANDAD_ID, tc.PARENT_ID
  from SYMPTOMS sc inner join TREE_C tc on sc.PARENT_ID = tc.IDD
)
select
  t.LEV, t.GRANDAD_ID, t.PARENT_ID, count(*)
from TREE_C t
group by 1, 2, 3

Пишет ошибку:
Column unknown
TC.IDD
At line 18, column 62
Хотя вроде имя столбца определено...
В чём проблема?

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

Ответить