powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / Иерархия и рекурсия
120 сообщений из 120, показаны все 5 страниц
Иерархия и рекурсия
    #32506661
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Windows XP, Office XP
Имеется:
Код: plaintext
1.
2.
3.
4.
5.
Таблица:	дети				Таблица: семьи
    Столбцы				    Столбцы
	Имя	Тип				Имя	Тип
	семья	Длинное целое	∞     -	 1 	id	Длинное целое (ключ)
	ребенок	Длинное целое			муж	Длинное целое
	счетчик	Длинное целое			жена	Длинное целое

Требуется найти всех потомков какой-либо персоны (например 29) и записать их и номер поколения в таблицу потомки.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
Option Compare Database
Option Explicit
  Dim dbs As Database, rstDesc As Recordset, rst As Recordset, n As Long

Sub start()
    Set dbs = CurrentDb
    Set rstDesc = dbs.OpenRecordset("SELECT * FROM потомки")
    FindDescendant  29 ,  1 
End Sub

Sub FindDescendant(id As Long, iGeneration As Long)
    On Error Resume Next
    Dim i As Long
    Set rst = dbs.OpenRecordset( _
        "SELECT ребенок FROM семьи LEFT JOIN дети ON семьи.id=дети.семья WHERE Not ребенок Is Null AND (муж=" _
        & id & " OR жена=" & id & ")")
    With rst
        Do While Not .EOF
            n = .Fields( 0 )
            With rstDesc
                .AddNew
                .Fields( 0 ) = n
                .Fields( 1 ) = iGeneration
                .Update
            End With
            i = iGeneration +  1 
            FindDescendant .Fields( 0 ), i
            .MoveNext
        Loop
    End With
End Sub
Когда потомков одна-две сотни, то время выполнения приемлемо.
При большем количестве производительнось катострофически падает.
Так за 30 мин определяется около 2500 потомков.
Посоветуйте, как существенно повысить производительность?
Все имеющееся на форумах прочел...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32506674
lobodava
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хорошо бы постановку задачи озвучить целиком. Типа есть то-то и то-то, получить надо вот это...
А то не понятно почему именно такие таблицы. Или это какая-то классическая компоновка о которой все знают?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32506686
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 lobodava
Эти таблицы - часть генеалогической базы данных, отображающие родственные отношения.
В общепринятом формате (так называемом GedCom стандарте) существуют два вида отношений:
а) персона - семья родителей (отец и мать);
б) персона - супруг(а) - дети.
Эти отношения, имхо, отражают предложенные таблицы. М.б. можно и по другому...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32506692
lobodava
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вау!!! А где почитать о GedCom стандарте? Ссылки есть?
А то ни как не пойму как цепочка выстраивается из тех таблиц, что предложены.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32506706
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Вижу логическую ошибку.

Переменная rst As Recordset описана на уровне модуля, однако при каждом обращении к процедуре FindDescendant этой переменной заново делается Set и какое-то количество раз MoveNext. При возврате из очередного обращения к FindDescendant эта переменная уже имеет совершенно не то значение, которое было ей дано перед входом туда.

По-моему, это должно вообще приводить к неправильной работе программы, а не то что к замедлению.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32506814
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 lobodava
Ссылок на стандарт можно найти мгого, только на английском. Например:
The GEDCOM Standard Release 5.5
The GEDCOM Standard Release 5.5 (pdf)
Кратко суть такова:
В текстовом файле последовательно размещаются:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
- персона (с уникальным ключом)
- ссылка на ключ семьи родителей
- ссылка на ключ своей семьи
далее другие персоны
...
- семья (с уникальным ключом)
- ссылка на ключ мужа
- ссылка на ключ жены
- ссылка на ключ  1  ребенка
- ссылка на ключ  2  ребенка и т.д.
Выглядит это так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
 0  @I1@ INDI
 1  NAME Иван Иванович /Иванов/
 1  SEX M
 1  FAMC @F2@
 1  FAMS @F1@
 0  @I2@ INDI
 1  NAME Марья Ивановна /Петрова/
 1  SEX F
 1  FAMC @F14@
 1  FAMS @F1@
 0  @I3@ INDI
 1  NAME Петр Иванович /Иванов/
 1  SEX M
 1  FAMC @F1@
 1  FAMS @F11@
 0  @I4@ INDI
 1  NAME Анна Ивановна /Иванова/
 1  SEX F
 1  FAMC @F1@
...
 0  @F1@ FAM
 1  HUSB @I1@
 1  WIFE @I2@
 1  CHIL @I3@
 1  CHIL @ 4 @
 0  @F2@ FAM
 1  HUSB @I10@
 1  WIFE @I11@
 1  CHIL @I1@
...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32506833
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Владимиру Санычу
авторПри возврате из очередного обращения к FindDescendant эта переменная уже имеет совершенно не то значение, которое было ей дано перед входом туда.
Именно так!
На этом и построен алгоритм:
Код: plaintext
1.
2.
3.
4.
 1 . Определяем детей персоны.
 2 . Определяем детей  1 -го ребенка.
 3 . Если у  1 -го ребенка детей нет, возвращаемся ко  2 -му ребенку
 4 . Если у  1 -го ребенка дети есть, определяем его детей
и т.д.
Проверено, работает правильно.
В прилагаемом текстовом файле есть реальные таблицы.
Можно было построить следующий алгоритм:
Код: plaintext
1.
2.
3.
 1 . Находим всех детей  1 -го ребенка.
 2 . Находим всех детей  2 -го ребенка.
 3 . Находим всех детей  1 -го ребенка  1 -го ребенка.
и т.д.
Правда, как это сделать и что лучше, не знаю ...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507021
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Но если написано

Set rst = dbs.OpenRecordset...
With rst
Do While Not .EOF
'***'
.MoveNext

то, наверно, .MoveNext и While Not .EOF должны относиться к тому же объекту, которому сделан Set. Однако в приведенной программе это не так, потому что в части '***' делается другой Set. Может, все-таки надо перенести Dim rst As Recordset внутрь процедуры?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507052
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторDim rst As Recordset внутрь процедуры?

Саныч, утечку памяти это не предотвратит - что в лоб, что по лбу
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507060
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Почему не предотвратит? Просто будет несколько экземпляров рекордсета, но каждый будет закрываться когда ему положено.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507064
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
кто же его закроет, если ему это явно не сказано?
А если сказано, то то и указатели в стеке плодить не обязательно - одного хватит, на уровне модуля.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507073
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Close надо добавить, это несомненно. Независимо ни от чего.

Но одного не хватит, потому что они должны использоваться одновременно. Второй должен открываться прежде, чем закроется первый, и т.д.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507075
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Саныч прав
должно выглядеть так (чтобы рекордсеты разных поколений, и счетчики поколений в рекурсии были автономными)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
Option Compare Database
Option Explicit
  Dim dbs As Database, rstDesc As Recordset

Sub start()
    Set dbs = CurrentDb
    Set rstDesc = dbs.OpenRecordset("SELECT * FROM потомки")
    FindDescendant  1 ,  1  ' 29 ,  1 
    rstDesc.Close
    Set rstDesc = Nothing
End Sub

Sub FindDescendant(id As Long, iGeneration As Long)
    On Error Resume Next
    Dim i As Long, rst As Recordset, n As Long
    Set rst = dbs.OpenRecordset(_
        "SELECT ребенок FROM семьи LEFT JOIN дети ON семьи.id=дети.семья WHERE Not ребенок Is Null AND (муж=" _
        & id & " OR жена=" & id & ")")
    With rst
        Do While Not .EOF
            n = .Fields( 0 )
            With rstDesc
                .AddNew
                .Fields( 0 ) = n
                .Fields( 1 ) = iGeneration
                .Update
            End With
            i = iGeneration +  1 
            FindDescendant .Fields( 0 ), i
            .MoveNext
        Loop
    End With
    rst.Close
    Set rst = Nothing
End Sub
т.е. ваш алгоритм крив.

по мужу и жене наверное надо бы залудить индексы. Но на больших объемах все равно будут проблемы - как вы думаете, сколько стоит взять несколько десятков тысяч разных запросов (да, не дай бог, с предварительной оптимизацией)?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507078
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Кстати! Вот если поставить Close, то тут-то и станет очевидно, что программа работает неправильно. Потому что после первого выполненного Close сразу начнутся сообщения об ошибках.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507088
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
то есть если ты про то, что процедура рекурсивный характер имеет (блин - должна иметь) - это несомненно. Но при этом рекордсет не обязателен. достаточно dcount-ом проверить, есть ли дети и и одним update-запросом. проставить им уровень.

ЗЫ
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507093
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
2 Victosha:
Полностью согласен.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507107
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Саныч

Стандарт!
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507114
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Владимир Саныч, 2 Victosha
Определенно вы друг-друга понимаете :)
Я вас - нет :(
Нельзя ли конкретизировать в виде кода?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507119
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
и самое главное. на размещение в памяти тысячи рекордсетов потребуется до шиша памяти. т.ч. может и имеет смысл обходиться одним рекордсетом, но по возвращении из рекурсии надо возобновлять _старый_ (т.е. _этого уровня_ наследственности) рекордсет, и вместо MoveNext ходить Find-ом на следующий.



еще одно решение - сделать поле муж/жена общим (персона) (+ поле признака (тип) + уникальный индекс по 3-м полям (семья,персона,тип), открывать семью не запросом, а рекордсетом по указанному индексу и бегать seek-ом (по возвращении во внешний уровень переходить seek-ом на следующее значение индекса). (то же можно и при разных полях мух/жана, но пробегая процедуру по 2-м индексам (семья,муж), (семья,жена))
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507129
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
Option Compare Database
Option Explicit
  Dim dbs As Database, rstDesc As Recordset, n As Long

Sub start()
    Set dbs = CurrentDb
    Set rstDesc = dbs.OpenRecordset("SELECT * FROM потомки")
    FindDescendant  29 ,  1 
End Sub

Sub FindDescendant(id As Long, iGeneration As Long)
Dim rst As Recordset '!!!'
    On Error Resume Next
    Dim i As Long
    Set rst = dbs.OpenRecordset( _
        "SELECT ребенок FROM семьи LEFT JOIN дети ON семьи.id=дети.семья WHERE Not ребенок Is Null AND (муж=" _
        & id & " OR жена=" & id & ")")
    With rst
        Do While Not .EOF
            n = .Fields( 0 )
            With rstDesc
                .AddNew
                .Fields( 0 ) = n
                .Fields( 1 ) = iGeneration
                .Update
            End With
            i = iGeneration +  1 
            FindDescendant .Fields( 0 ), i
            .MoveNext
        Loop
        .Close '!!!'
    End With
End Sub

Это без учета того, что сказали фыыф и Victosha. Потому что они абсолютно правы, но это потребует более серьезных изменений.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507149
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Да, действительно, надо выбросить (многократные, и затратные) открытия рекордсетов из рекурсии. Открывать один раз один набор семей снаружи, как dbOpenTable, и при входе/возвращении на уровень изменять только параметры Seek-а (много быстрее чем Find), для чего озаботиться необходимыми индексами и переменными уровня рекурсивной процедуры для их текущего хранения. Это (для mdb) будет наискорейшим выходом.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507177
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыв

модификация - на ado открыь 2 client-side рекордсета, локально их индексировать, дальше и FindFirst (не вижу зачем) и Filter их будут успешно пользовать. Рекурсию придется линеаризировать циклами.

ps
кто ж такие "потомки" - что-то в "ТЗ" их не наблюдается ?....
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507268
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Владимир Саныч
Проверил работу твоего кода. Производительность не изменилась :(
Кстати, объявление переменных в рекурсивных процедурах уменьшает память.
Это не я сказал :)
Рекомендуют объявлять их на уровне модуля.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507274
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Victosha
авторкто ж такие "потомки" - что-то в "ТЗ" их не наблюдается ?....
Не пойму, в чем вопрос?
Родитель > ребенок > его ребенок > и т.д.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507277
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Я не говорил о производительности. Я говорил о правильности. Если несколько рекурсивно вызванных экземпляров процедуры пользуются одним и тем же экземпляром некой переменной, то возникает конфликт!
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507283
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
автор... для чего озаботиться необходимыми индексами и переменными уровня рекурсивной процедуры для их текущего хранения.
Нельзя ли по-подробнее.
Я с этого начинал и пришел в тупик. Скорее всего по собственной ...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507292
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Владимир Саныч
Очевидно так.
Но конфликтов у меня не происходило.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507309
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Victosha
автормодификация - на ado открыь 2 client-side рекордсета, локально их индексировать, дальше и FindFirst (не вижу зачем) и Filter их будут успешно пользовать. Рекурсию придется линеаризировать циклами.
С ado не работал. Если не в лом, напиши реализацию.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507362
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Попробуй что-то в этом роде:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
Option Compare Database
Option Explicit
  Dim dbs As Database, rstDesc As Recordset, rstS As Recordset, rstD As Recordset ', n As Long

Sub startT()
    Set dbs = CurrentDb
    dbs.Execute ("Delete From потомки")
    Set rstDesc = dbs.OpenRecordset("потомки")
    Set rstS = dbs.OpenRecordset("семьи", dbOpenTable)
    Set rstD = dbs.OpenRecordset("дети", dbOpenTable)
    rstD.Index = "СемьяРебенок"
    FindDescendantT 1, 1 '29,  1 
    rstDesc.Close
    Set rstDesc = Nothing
    rstS.Close
    Set rstS = Nothing
    rstD.Close
    Set rstD = Nothing
End Sub

Sub FindDescendantT(id As Long, iGeneration As Long)
    On Error Resume Next
    Dim i As Long, nS As Long, nR As Long, iSx As Long
    Dim sIn( 0  To  1 ) As String
    sIn( 0 ) = "Мid": sIn( 1 ) = "Жid"
    For iSx =  0  To  1 
        With rstS
            .Index = sIn(iSx)
            .Seek ">=", id,  0 
            If Not .NoMatch Then
                Do While .Fields(iSx +  1 ) = id
                    nS = .Fields("id")
                    With rstD
                        .Seek ">=", nS,  0 
                        If Not rstD.NoMatch Then
                            Do While .Fields("Семья") = nS
                                nR = .Fields("Ребенок")
                                With rstDesc
                                    .AddNew
                                    .Fields( 0 ) = nR
                                    .Fields( 1 ) = iGeneration
                                    .Update
                                End With
                                i = iGeneration +  1 
                                FindDescendantT nR, i
                                .Seek ">", nS, nR
                                If .NoMatch Then Exit Do
                            Loop
                        End If
                    End With
                    .Index = sIn(iSx) 'мог смениться
                    .Seek ">", id, nS
                    If .NoMatch Then Exit Do
                Loop
            End If
        End With
    Next iSx
End Sub
Где sIn(0) = "Мid": sIn(1) = "Жid" - соответственные индексы в семье (муж,id), (жена,id), СемьяРебенок - в "детях", возрастающие по обоим полям. Отладил вчерне. Мож что поизячней нарисуешь.


По поводу "конфликта" саныч неправильно выразился. Там не будет конфликта программного (если не закрывать рекордсеты на уровнях явным образом). Там при возврате из вложенной процедуры будешь иметь совсем не тот рекордсет, который был задан на ЭТОМ уровне рекурсии (он переопределится на другом). Т.е. "конфликт" логический.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507369
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
фыыфПо поводу "конфликта" саныч неправильно выразился... Т.е. "конфликт" логический.
А я и не говорил, что будет какой-то иной конфликт, кроме логического...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507393
lobodava
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот тебе и на!!!
Ушёл решать задачку когда шесть постов было, а пришёл - топик на двух страницах уже. Круто!!!

Предлагаю свой вариант без использования рекурсии.
Прикреплённый файл для Access 2000
Данные из этого поста
Самый плодовитый предок под номером 65
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507471
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 lobodava
На работе экран стоит :(
Скачать нельзя.
Посмотрю только дома, спасибо!
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507478
Фотография Владимир Саныч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Копирую решение lobodava сюда:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
Public Sub FindDescendants(PersonID As Integer) 'PersonID - Papa or Mama
    Dim strSQL As String
    Dim cmd As ADODB.Command
    Dim lngRecordsEffected As Long
    Dim i As Integer

    Set cmd = New ADODB.Command
    cmd.ActiveConnection = CurrentProject.Connection
    cmd.CommandType = adCmdText

    strSQL = "DELETE * FROM tblDescendants"
    cmd.CommandText = strSQL
    cmd.Execute

    strSQL = "INSERT INTO tblDescendants ( Kid, Generation ) " & _
            "SELECT tblKids.Kid,  1  AS Generation " & _
            "FROM tblFAM LEFT JOIN tblKids ON tblFAM.Fam = tblKids.Fam " & _
            "WHERE Not tblKids.Kid Is Null AND (tblFAM.Papa = " & PersonID & " OR tblFAM.Mama = " & PersonID & ");"

    cmd.CommandText = strSQL
    cmd.Execute lngRecordsEffected

    i =  1 
    Do Until lngRecordsEffected =  0 
        strSQL = "INSERT INTO tblDescendants ( Kid, Generation ) " & _
                 "SELECT DISTINCT tblKids.Kid, " & Str(i +  1 ) & " AS Generation " & _
        "FROM tblDescendants INNER JOIN (tblFam LEFT JOIN tblKids ON tblFam.Fam = tblKids.Fam) " & _
        "ON tblDescendants.Kid = tblFam.Papa OR tblDescendants.Kid = tblFam.Mama " & _
        "WHERE tblDescendants.Generation = " & Str(i) & " And  Not tblKids.Kid Is Null"

        cmd.CommandText = strSQL
        cmd.Execute lngRecordsEffected

        i = i +  1 
    Loop
End Sub
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507501
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Владимир Саныч, весьма признателен!
2 lobodava:
авторСамый плодовитый предок под номером 65
61 д.б. таким же - они супруги! :)
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507502
lobodava
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблицы:
tblFam: Fam, Papa, Mama
tblKids: Kid, Fam, ID
tblDescendants: Kid, Generation

В последнюю таблицу записываются все потомки PersonID и их поколение
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507510
lobodava
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
автор61 д.б. таким же - они супруги! :)
Понятное дело
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507600
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
lobodava, увы...
Время работы на больших таблицах осталось прежним.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507613
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
авторд.б. таким же - они супруги

ответ неверный. есть случаи нескольких семей у персоны. гаремы, опять же. и бастарды. :о)
и все равно прогонка по индексированному рекордсету (курсору - на сервере) должна работать (в данном случае) быстрее нескольких запросов. А именно - за счет "подготовки" запросов.


Да, и в случае разделенных данных/кода вместо set dbs=currentDb, открывай DB данных.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507639
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
авторВремя работы на больших таблицах осталось прежним
не мудрено, если таблицы не индексированы по полям, по которым идет поиск (тут, у лободавы, не помешают индексы (Fam,Papa) и (Fam,Mama), причем как будут себя вести индексы при OR в ON в JOIN-е фих его знает. Возможно лучше (для больших таблиц) разбить запросы на 2 запроса - отельно по папам и отдельно по мамам).
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507642
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
авторответ неверный
Все так. Но в конкретном случае других браков не было :)
А по сути предложенного решения - разбираюсь с индексами.
Можно по-четче (для меня): у каких полей какие индексы?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507660
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
для процедуры прогонки по рекордсету индексы (их имена) приведены в коде, состав полей - под ним.

для запросов со связями (или со сложным WHERE) индексы должны быть по возможности отсеивающими большую часть таблиц по условию. Для связи по нескольким полям - индексы должны быть составными по всем полям связи (если такая связь не определена как связь с поддержанием целостности на уровне схемы данных - т.к. в последнем случае Аксесом автоматически создаются служебные индексы (вторичные ключи), не отображаемые во вкладке "индексы" таблицы). Причем они должны быть одинаково структурированными для обеих связываемых таблиц..
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32507671
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
почетче
в tblFam у полей Fam,Papa,Mama поставь в конструкторе таблиц свойство "индексирован=Да(допускаются совпадения)"
в tblKids сделай то же для поля Fam
в tblDescendants для поля Kid и сделайте составной индекс (Generation,Kid)

PS
тип: преобразовав в простой селект, сохраните запрос как стандартный запрос акцесс и натравите на него Сервис->Анализ->Быстродействие
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32508458
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
Разобрался с индексами в вашем коде.
Проверил - начинает работать шустро, но...
После найденных одной-двух тысяч потомков работа практически останавливаетя. Что-то переполняется (память, кэш ???).
Есть ли какие соображения?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32508850
Фотография Zenia
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а ты не пробовал перед открытием рекордсета определить что ты будешь сним делать

Код: plaintext
1.
2.
3.
4.
Set rstDesc = dbs.OpenRecordset("SELECT * FROM потомки", dbAppendOnly)

Set rst = dbs.OpenRecordset(_  
            "SELECT ребенок FROM семьи LEFT JOIN дети ON семьи.id=дети.семья WHERE Not ребенок Is Null AND (муж=" _        
           & id & " OR жена=" & id & ")", dbOpenForwardOnly)
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32508951
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Zenia
Проверил.
Результат тот же :(
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32508959
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
соображения такие:
рекурсия приводит к сохранению на каждом уровне переменных уровня рекурсии

Dim i As Long, nS As Long, nR As Long, iSx As Long
Dim sIn(0 To 1) As String

не думаю, что пара тысяч этих переменных убьет процесс. Но вот каждая процедура должна при рекурсии еще и помнить, куда она должна вернуть результат/управление. Что там происходит - а бог его знает.

Посему, если грешить на рекурсию и переполнения, а не на банальный баг, который где-то недочищен (и зацикливает процедуру при редком сочетании данных), имеет смысл избавиться от рекурсии. Идея - в решении lobodava (в циклическом переборе по поколениям).


Но, видимо, имеет смысл не выполнять запросы, а в предложенном мной цикле выбросить рекурсивный вызов процедурой самой-себя, добавить параметры вызова (вернее - переменные уровня модуля), необходимые для нового вызова процедуры для следующего поколения из внешней процедуры-цикла (видимо - 2 массива: 1. массив потомков данного уровня, 2. массив потомков следующего, и, возможно, номер уровня) а во внешней процедуре вызывать процедуру в двойном цикле - до возврата пустого массива потомков следующего уровня, а во внутреннем цикле (двойного, внешней процедуры) - и осуществлять вызов - по массиву потомков текущего уровня (заполняя одновременно массив следующего). Почему массивы? Потому что иначе придется повторять операции чтения (вытягивать данные запросами, пусть и по индексированным таблицам), что дольше.


предполагаемый выигрыш: - освобождение от рекурсий и вместо смены индекса и поиска практически всякий раз Seek-ом, можно после первого Seek делать просто MoveNext (индекс то задан, и не меняется ни он, ни положение текущей записи в рекурсивных вызовах), до выхода по сравнению ключа. Что быстрее.

затраты: - 2 массива Long, переменной длинны, объявленные на уровне модуля, приватные; но на потомков только одного уровня (если будем вычислять потомков Адама или Евы, боюсь, памяти простой персоналки не хватит, но и запросы на таких объемах - не фонтан, результаты же их все равно надо куда-то складывать, если только не пытаться открыть рекордсет с последовательным доступом и т.п...). + Минимальная переделка процедуры FindDescendantT (выброска ре-Seek-ов и ре-Index; замена самовызова на блок пополнения массива потомков следующего уровня); и написание процедуры ее вызова как FindDescendantT(Pc(i), iGeneration) в цикле. (первый вызов - как и было).

Вот только не найдем ли мы в итоге логический "баг", наподобие ошибки в данных - нахождение кольца по предкам/потомкам? Или еще чего.

___
ЗЫ : ДА, есть теоретический вопрос. Если пипл является потомком другого более чем одного уровня (по паре веток разной длинны), то и его потомки будут дважды считаться в таблице потомков :). Что об этом случае думает генеология? (хорошо, что чел не может быть собственным предком, но база, кстати, об этом не знает - если нет триггеров/правил, отслеживающих кольца).
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32508961
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
1)
попробуй поставить
DBEngine.Idle

перед Next iSx

2)
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32508993
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Результат работы кода фыыф'а (самого быстрого):
Время Кол-во записей
1 сек. 4500
5 сек. 5500
10 сек. 6000
15 сек. 6100
и далее в той же прогрессии.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32508999
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
и все таки мыслится, что если процедура именно "останавливается", то надо посмотреть на вероятные баги в режиме отладки (уж очень мало). Очень может быть, что чегой-то я недоглядел.

Но есть и идейка о том, что задалбливают перечтения индексов, количество которых (перечтений) растет быстрее, чем число потомков (по возвращению из рекурсий со сменой пола - новое перечтение). Одна надежда, что индексы в кеш влезают.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509007
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
еще раз: попробуй поставить DBEngine.Idle
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509008
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Victosha
Увы :(
А что под № 2) ?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509014
Фотография Zenia
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
'а зачем LEFT JOIN
Set rst = dbs.OpenRecordset(_  
            "SELECT ребенок FROM семьи LEFT JOIN дети ON семьи.id=дети.семья WHERE Not ребенок Is Null AND (муж=" _        
           & id & " OR жена=" & id & ")", dbOpenForwardOnly)

'можно сократить
Set rst = dbs.OpenRecordset(_  
            "SELECT ребенок FROM семьи INNER JOIN дети ON семьи.id=дети.семья" _ 
& "WHERE муж=" & id & " OR жена=" & id & ")", dbOpenForwardOnly)
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509015
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2) - минорный улучшайзинг- закешируй обращения к полям и используй .Collect
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509021
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
Вы очень хорошо обо мне думаете :)
Мне только, чтобы разобраться в смысле написанного потребуется день!
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509034
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Victosha
Что это Collect?
В справке не нашел.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509038
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
давай еще раз попробуем
1) DBENgine.Idle dbRefreshCache

2 ) перед AddNew поставь DBENgine.BeginTrans
после Update поставь DBEngine.CommitTrans
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509042
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
о! идея (находюся)

откройте 2 рекордсета rstS(0 to 1)
и сразу при открытии один раз (не в рекурсивной части)

Код: plaintext
1.
2.
3.
    sIn( 0 ) = "Мid": sIn( 1 ) = "Жid"
    For iSx =  0  To  1         
        rstS(iSx).Index = sIn(iSx)
    next iSx
а в рекурсивной переключаться меж рекордсетами, а не менять индекс:

Код: plaintext
1.
2.
3.
4.
5.
    For iSx =  0  To  1 
        With rstS(iSx)
            '.Index = sIn(iSx) - уже задан, не будем!'
            ...
                    End With
                    '.Index = sIn(iSx) 'НЕ мог смениться
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509048
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Zenia
Есть семьи без детей. В какой-то версии возникала ошибка.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509063
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
пардон Collect - соврал - он - .CollectionIndex - недокументированный и самый быстрый способ обращения к значению поля для DAO.Recordset
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509069
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Victosha
Проверил. Без улучшения.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
Sub FindDescendantT(id As Long, iGeneration As Long)
    On Error Resume Next
    Dim i As Long, nS As Long, nR As Long, iSx As Long
    Dim sIn( 0  To  1 ) As String
    sIn( 0 ) = "муж": sIn( 1 ) = "жена"
    For iSx =  0  To  1 
        With rstS
            .Index = sIn(iSx)
            .Seek ">=", id
            If Not .NoMatch Then
                Do While .Fields(iSx +  1 ) = id
                    nS = .Fields("id")
                    With rstD
                        .Seek ">=", nS,  0 
                        If Not rstD.NoMatch Then
                            Do While .Fields("Семья") = nS
                                nR = .Fields("Ребенок")
                                With rstDesc
                                    DBEngine.BeginTrans
                                    .AddNew
                                    .Fields( 0 ) = nR
                                    .Fields( 1 ) = iGeneration
                                    .Update
                                    DBEngine.CommitTrans
                                End With
                                i = iGeneration +  1 
                                FindDescendantT nR, i
                                .Seek ">", nS, nR
                                If .NoMatch Then Exit Do
                            Loop
                        End If
                    End With
                    .Index = sIn(iSx) 'мог смениться
                    .Seek ">", id, nS
                    If .NoMatch Then Exit Do
                Loop
            End If
        End With
        DBEngine.Idle dbRefreshCache
    Next iSx
End Sub
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509074
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
т.е. (с учетом "хорошо думаю") попробуйте вот так: (и приведите результаты, если не сложно)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
Option Compare Database
Option Explicit
  Dim dbs As Database, rstDesc As Recordset, rstS( 0  To  1 ) As Recordset, rstD As Recordset ', n As Long
  Private Pc(0 To 0) As Long, Pn(0 To 0) As Long

Sub startM()
    Dim iSx As Long
    Dim sIn(0 To 1) As String
    Set dbs = CurrentDb
    dbs.Execute ("Delete From потомки")
    Set rstDesc = dbs.OpenRecordset("потомки")
    
    sIn(0) = "Мid": sIn(1) = "Жid"
    For iSx = 0 To 1
        Set rstS(iSx) = dbs.OpenRecordset("семьи", dbOpenTable)
        rstS(iSx).Index = sIn(iSx)
    Next iSx

    Set rstD = dbs.OpenRecordset("дети", dbOpenTable)
    rstD.Index = "СемьяРебенок"
    FindDescendantM 1, 1 '29,  1 
    rstDesc.Close
    Set rstDesc = Nothing
    For iSx =  0  To  1 
        rstS(iSx).Close
        Set rstS(iSx) = Nothing
    Next iSx
    rstD.Close
    Set rstD = Nothing
End Sub

Sub FindDescendantM(id As Long, iGeneration As Long)
    On Error Resume Next
    Dim i As Long, nS As Long, nR As Long, iSx As Long
    'Set rst = dbs.OpenRecordset("SELECT ребенок FROM семьи LEFT JOIN дети ON семьи.id=дети.семья WHERE Not ребенок Is Null AND (муж=" & id & " OR жена=" & id & ")")
    Dim sIn(0 To 1) As String
    sIn(0) = "Мid": sIn(1) = "Жid"
    For iSx = 0 To 1
        With rstS(iSx)
            '.Index = sIn(iSx)
            .Seek ">=", id,  0 
            If Not .NoMatch Then
                Do While .Fields(iSx +  1 ) = id
                    nS = .Fields("id")
                    With rstD
                        .Seek ">=", nS,  0 
                        If Not rstD.NoMatch Then
                            Do While .Fields("Семья") = nS
                                nR = .Fields("Ребенок")
                                With rstDesc
                                    .AddNew
                                    .Fields( 0 ) = nR
                                    .Fields( 1 ) = iGeneration
                                    .Update
                                End With
                                i = iGeneration +  1 
                                FindDescendantM nR, i
                                .Seek ">", nS, nR
                                If .NoMatch Then Exit Do
                            Loop
                        End If
                    End With
                    '.Index = sIn(iSx) 'мог смениться
                    .Seek ">", id, nS
                    If .NoMatch Then Exit Do
                Loop
            End If
        End With
    Next iSx
End Sub
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509080
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
блин, просмотрел!
- выкиньте еще:
Dim sIn(0 To 1) As String
sIn(0) = "Мid": sIn(1) = "Жid"
из рекурсивной части
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509084
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
авторо! идея (находюся)
Я не успеваю за вами.
Нельзя ли идею в полном виде?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509096
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
именно к этому "идея" см. полный код 13:45 + примечание 13:47


главное - есть ли профит (от неперечтения индексов, но с платой - лишним рекордсетом)
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509109
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
Профита нет. Совсем :(
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509113
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну вот еще один заход шаманский - не уверен, что поможет, но результат услышать бы хотелось.

попробуй после DBEngine.Idle
поставить DoEvents
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509114
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
именно те же количества? за те же времена?
а вызывали вы именно FindDescendantM
(с помощью startM),
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509167
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
что-то я сегодня совсем зарапартовался- видно спать пора -
CollectionIndex - он, конечно, не значение возвращает, а номер поля в наборе данных

пошел спать
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509170
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
Запускал из нового модуля, так что без ошибок (своих :0) )...
Результаты теже.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509195
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Victosha
авторпопробуй после DBEngine.Idle
поставить DoEvents
По прежнему...
авторпошел спать
Спокойного сна!
Возвращайся! :)
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509227
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ну, попробу так (без рекурсий)
что-то сомневаюсь я, но все таки должен быть другой тип зависимости времени от числа возвращенных записей:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
Option Compare Database
Option Explicit
Private dbs As Database, rstDesc As Recordset, rstS( 0  To  1 ) As Recordset, rstD As Recordset ', n As Long
Private pC() As Long, pN() As Long

Sub startA()
    Dim iSx As Long
    Dim sIn(0 To 1) As String
    Set dbs = CurrentDb
    dbs.Execute ("Delete From потомки")
    Set rstDesc = dbs.OpenRecordset("потомки")
    
    sIn(0) = "Мid": sIn(1) = "Жid"
    For iSx = 0 To 1
        Set rstS(iSx) = dbs.OpenRecordset("семьи", dbOpenTable)
        rstS(iSx).Index = sIn(iSx)
    Next iSx

    Set rstD = dbs.OpenRecordset("дети", dbOpenTable)
    rstD.Index = "СемьяРебенок"
    FindDescendantAll 1, 1 '29,  1 
    rstDesc.Close
    Set rstDesc = Nothing
    For iSx =  0  To  1 
        rstS(iSx).Close
        Set rstS(iSx) = Nothing
    Next iSx
    rstD.Close
    Set rstD = Nothing
End Sub

Sub FindDescendantAll(id As Long, iGeneration As Long)
Dim nP As Long, nC As Long, iG As Long, bF As Boolean
Dim iC As Long

    On Error Resume Next
    bF = FindDescendantA(id, iGeneration)   'первый вызов
    iG = iGeneration
    Do While bF  'цикл по поколениям
        If (bF) Then  'лишняя проверка, осталась от отладки :)
            'переместим следующих в текущий
            Erase pC
            ReDim pC( 0  To UBound(pN))
            For iC =  0  To UBound(pN)
                pC(iC) = pN(iC)
            Next iC
        End If
        Erase pN    'очистка следующего
        bF = False
        iG = iG + 1
        For nC = 0 To UBound(pC)
            bF = FindDescendantA(pC(nC), iG) Or bF
        Next nC
    Loop
End Sub

Function FindDescendantA(id As Long, iGeneration As Long) As Boolean
    Dim i As Long, nS As Long, nR As Long, iSx As Long
    On Error Resume Next        
    For iSx = 0 To 1
        With rstS(iSx)
            '.Index = sIn(iSx)
            .Seek ">=", id,  0 
            If Not .NoMatch Then
                Do While .Fields(iSx +  1 ) = id
                    nS = .Fields("id")
                    With rstD
                        .Seek ">=", nS,  0 
                        If Not rstD.NoMatch Then
                            Do While .Fields("Семья") = nS
                                nR = .Fields("Ребенок")
                                With rstDesc
                                    .AddNew
                                    .Fields( 0 ) = nR
                                    .Fields( 1 ) = iGeneration
                                    .Update
                                End With
                                i = iGeneration +  1 
                                FindDescendantA = True 'есть хоть один
                                'FindDescendantA nR, i
                                Dim kN As Long
                                kN = UBound(pN) +  1 
                                ReDim Preserve pN( 0  To kN)
                                pN(kN) = nR 'вызовем потом
                                '.Seek ">", nS, nR
                                .MoveNext
                                If .NoMatch Then Exit Do
                            Loop
                        End If
                    End With
                    '.Seek ">", id, nS
                    .MoveNext
                    If .NoMatch Then Exit Do
                Loop
            End If
        End With
    Next iSx
End Function

обрати внимание на вызовы (имена :). И приведи таки вид зависимости от времени.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509251
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
проснулся

СТОП - а потомки там часом не индексированы ли ?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509348
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2 Victosha

мдя, я тут не фигней ли занимаюсь в поэлементном присвоении массива?
Нельзя ли его как-то с помощью передачи указателя(ей) передвинуть?


ЗЫ (была как-то задачка, для которой тип. содержащий коллекции и массивы (не помню, но кажется массивы с членами - коллекциями) неплохо б было клонировать. Так там тоже было бы невредно исхитрятся без поэлементного присвоении, только там область памяти как-то надо было еще "сдвигать" (а стало быть и все указатели на объектные поля типа) - после клонирования действия над объектами (коллекциями и их членами) были разные).
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509354
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф

1) собственно массива "на присвоение" я тут не проглядываю,
2) в переводе с русского на русский - сие есть глубокий хакинг, применительно к тому месту о котором ты говоришь - надо в DAO SDK углубляться - я этого не делал.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509388
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2 Victosha

это я спрашал исключительно про кусок нерекурсивного варианта (последнего из предложенных), касательно сдвига следующего поколения в текущий:
Код: plaintext
1.
2.
3.
4.
            Erase pC
            ReDim pC( 0  To UBound(pN))
            For iC =  0  To UBound(pN)
                pC(iC) = pN(iC)
            Next iC


_______________
ЗЫ. а задачка со сдвигом/клонированием объектов возникла при идее использовать "человеческие" описания "генов" в генетическом алгоритме (типы со значащими полями, а не строки бит) для конкретной задачки.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509414
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
да
в случае
Erase pC
ReDim pC(0 To UBound(pN))
For iC = 0 To UBound(pN)
pC(iC) = pN(iC)
Next iC

можно воспользоваться API функцией rtlMoveMemory (часто используемое подстановочное имя - CopyMemory) ()

Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)

тогда, навскидку, строка будет выглядеть примерно так

CopyMemory pC(0), pN(0), x*(UBound(pN)+1)
где x - количество байт в элементе массива - для инт - 2 для лонга 4

будет работать для любого линейного массива, в том числе для массива строк фиксированной длины.

видимость эффекта на самом деле сильно сависит от длины массива.
Дело в том, что вызов API- функций - относительно дорогая операция и для маленьких массивов эффективность копирования сожрется накладными расходами по вызову

Расходы можно чуть уменьшить , загрузив (в данном случае kernel32) в адресное пространство акцесса - я, правда, так не делаю.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509424
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
1 сек. 5000
5 сек. 5890
далее кол-во не изменяется, цикл продолжается.
Причина не ясна.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509451
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не выходит из цикла Function FindDescendantA
Переданное ей id имеет значение, не содержащееся в таблицах.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509474
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
автордалее кол-во не изменяется, цикл продолжается.
Причина не ясна.

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

1.Запаузь Ctrl+Break (при работе, в момент "причина не ясна")
(посмотри, заодно, какая ф-я крутится)
2.Включи в настройках режим прерывания "при любой ошибке" (не сбрасывая процедуру).
3.продолжи -
( Например объектная переменная в отсутствии, или за границу массивов вылетаем - кривой код и т.п.)

если ошибок нет (прерывающих прогу), то ошибка в логике циклов, или данных, тогда опять:
4. запаузь,
5.поставь точки останова на While-ах и Do
6.и посмотри, как крутится, почему не попадает на присвоение и не выходит наружу. (то ли поколения не сдвигаются, то ли еще какая мототень, и нет ли одноименных Public переменных.).

Заодно приведи размеры массивов поколений
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509492
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
за выход отвечает
Do While .Fields(iSx + 1) = id

если поля в таблице переместились(их индексы не 1 и 2), то вместо (iSx + 1) надо в явном виде задавть имена полей ("муж", "жена").
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509517
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
и шибко похоже, что у тебя нет объектной переменной, или ты за границами массивов.


В конечной реализации обработку ошибок надо сделать правильно. (В зависимости от того, нужны ли частичные результаты, не нужны никакие, нужно ли сообщение и т.п.
а не On Error Resume Next, которая в таких случаях приводит к бесконечному циклу).

зы: надеюсь ремарки ' со старого кода ты не снимал.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509521
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
Уже ничего не соображаю :(
Нужно начать сначала и упростить задачу.
Определять только потомков, без поколений.
М.б. писать их в массив, а не в таблицу (это быстрее или нет?).
Если это возможно, не мог бы я передать вам таблицы?
Не примите за нахальство - делаю не для денег, просто есть заинтересованный круг людей, занимающихся генеалогией.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509548
Фотография Zenia
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторЕсли это возможно, не мог бы я передать вам таблицы?

хорошая идея
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509573
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
16:23
- краткий курс отладчика.
Довольно полный, для вашего случая.
Попробуйте добить до конца.

цикл, даже если в него попала байда, должен выплюнуть. Если он крутиться - вероятно за счет отсутствия объектной переменной, к которым отсылаются сравнения While
(и конструкции On error resume Next, приписанной сюда от балды, закомментируйте ее на крайняк перед следующим запуском).



Есть вероятность моего логического бага (кроме пресловутой ошибки), но я его не вижу.


а файл, мне мниться, размером под гигабайт. Я его не съем :).
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509599
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2 Victosha
16:05
Спасибо. "Будем посмотреть".
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509700
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
автора файл, мне мниться, размером под гигабайт. Я его не съем :).
600 кб две таблицы в сжатом текстовом файле.
Как скажете...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509728
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нашел махоньки баг:

добавь:
Код: plaintext
1.
2.
3.
4.
Function UBoundE(Ar As Variant) As Long
On Error Resume Next
    UBoundE = UBound(Ar)
    If Err <>  0  Then UBoundE = - 1 
End Function
и замени в функции переопределение:
Код: plaintext
1.
2.
                                Dim kN As Long
                                kN = UBoundE(pN) +  1  'UBound(pN) +  1  
                                ReDim Preserve pN( 0  To kN)
это должно помочь с "зацикливанием".
(после Erase, UBound не рюхает. Не сразу понял. Старый стал. Глюпий. Мои извинения)



_________
2 Victosha.
Работает, кажется Ваш рецептик:

Erase pC
ReDim pC(0 To UBoundE(pN))
CopyMemory pC(0), pN(0), 4 * (UBoundE(pN) + 1)

но на моем объеме (в этой задаче) времена гуляют в обоих случаях на 2 порядка (очень мало данных, соответсвенно маленькие массивы), пришлось гонять в цикле всю процедуру по 100 раз. Времена совпадают в пределах ошибки. (т.е. полное время процедуры мало зависит от копирования (маленьких) массивов, и сл-но, метода.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509735
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: plaintext
 600  кб две таблицы в сжатом текстовом файле

Боюсь, почта от вас не дойдет. - На общедоступные почтовики я не ходок. И почта с общедоступных не проходит. Если только выложите где -нть на доступном месте (по http).
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509749
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
5890 ...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509753
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
А zip с сайта заберете?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509759
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
если сайт не закрыт моей проксей, заберу. Давайте адрес.

а что такое
5890 ...
?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509780
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Две упакованные таблицы. Берите.
5890 записей - получился тот же результат, что и до последнего исправления. На нем зацикливается.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509788
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыв

я, конечно, взрослый мальчик, но ко мне на ты легко.

ЗЫ
с с копимемори главная проблема "попасть в вызов" где ему byVal отдать, а где ByRef. Моя мозговая кость не так остра, чтобы положиться без проверки. Вот и поосторожничал в выражениях.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509798
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
а какой id предка вызывает такие длинные деревья?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509801
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 All
Для затравки :)
Есть программа, по моему на Дельфи, которая находит в этих файлах более 30000 потомков и записывает их в листбокс за 40 сек. Ну не совсем в этих, а преобразованных ей самой из gedcom файла.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509807
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
автора какой id предка вызывает такие длинные деревья?
29
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509808
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У №29, судя по той программе должно быть 33047 потомков
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509820
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
есть баги.
во всех версиях строки:
If .NoMatch Then Exit Do
замени на:
If .NoMatch Or .EOF Then Exit Do

но есть еще какая-то лажа-с.
на 7-м id рекурсивный алгоритм (2-й) накидал мне уже 12078, и не собирается останавливаться.


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

так же ведет себя и нерекурсивный.

буду смотреть завтра :).
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509821
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ссори, накидал болше 120000, куда то цифирь делась
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509898
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Записал с каждым найденным потомком текущее время. Группировка по времени, число записей.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509958
lobodava
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По таблицам:

148 и 149 (четвертое поколение от 29) - брат и сестра!!! Инцест налицо.
Не исключено что таких пар больше чем одна.
По моему алгоритму их потомки считаются дважды.

а 93907 - это вообще гермафродит - то он жена, то муж.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32509989
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 lobodava
В этой жизни и не такое возможно :)
Между прочим, это родичи Рюрика...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32510394
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
вероятно, проблема во внутрисемейных браках между поколениями. За счет этого число вхождений потомка в таблицу быстро растет.

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

Пока я не вижу быстрого роста числа входений одной и той же выделенной группы лиц (может быть группа и есть, но "слабо изолирована" - т.е. имеет множество "непетлевых" потомков, число входений которых в группу растет. Но, мне кажется, это пока не подверждается)

запускаем (у меня таблица "потомки" не индексирована !!! - т.е. возможно многократное повторение вставки потомка на уровень):
Start(7)
при числе потомков 155090 (не дожидаясь окончания счета) прерываемся и видим:
Код: plaintext
1.
2.
3.
4.
5.
6.
Ребенок	Dlt	MaxG	MinG	Cnt
 72771 	 8 	 39 	 31 	 90 
 72768 	 8 	 38 	 30 	 90 
 72767 	 8 	 38 	 30 	 90 
 72766 	 8 	 38 	 30 	 90 
 54240 	 8 	 40 	 32 	 87 
 54223 	 8 	 39 	 31 	 87 

это запрос вида:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SELECT потомки.Ребенок,
 Max([iGeneration])-Min([iGeneration]) AS Dlt,
 Max(потомки.iGeneration) AS MaxG,
 Min(потомки.iGeneration) AS MinG,
 Count(*) AS Cnt
FROM потомки
GROUP BY потомки.Ребенок
HAVING (((Count(*))> 1 ))
ORDER BY Max([iGeneration])-Min([iGeneration]) DESC ,
 Count(*) DESC ,
 Max(потомки.iGeneration) DESC ,
 Min(потомки.iGeneration);

и
Код: plaintext
1.
2.
3.
4.
5.
6.
Ребенок	Dlt	MaxG	MinG	Cnt
 29018 	 5 	 39 	 34 	 421 
 29017 	 5 	 39 	 34 	 421 
 29019 	 5 	 39 	 34 	 421 
 29020 	 5 	 39 	 34 	 421 
 29021 	 5 	 39 	 34 	 421 
 29015 	 5 	 38 	 33 	 237 
для
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SELECT потомки.Ребенок,
 Max([iGeneration])-Min([iGeneration]) AS Dlt,
 Max(потомки.iGeneration) AS MaxG,
 Min(потомки.iGeneration) AS MinG,
 Count(*) AS Cnt
FROM потомки
GROUP BY потомки.Ребенок
HAVING (((Count(*))> 1 ))
ORDER BY Count(*) DESC ,
 Max([iGeneration])-Min([iGeneration]) DESC ,
 Max(потомки.iGeneration) DESC ,
 Min(потомки.iGeneration);
т.е. некие люди потомки одного - 421 раз! (по 421 линиям, правда, вероятно с множественными пересечениями.


О графике:
Именно потому, что количество потомков на уровень быстро растет, видимо будут расти и размеры массивов текущего/следующего уровня при нерекурсивной процедуре. А это потребует изрядного времени на их копирование (из одного в другой).

При наличии уникальных индексов в таблице потомков, будет расти время работы вхолостую (попытки вставить имеющейся пары (потомок,уровень)

Если надо найти только потомков (т.е. хотя бы одно вхождение), то скорость счета можно увеличить, отбрасывая повторные вхождения потомка в набор (в другом поколении).

___
Как ускорить текущую задачу:
1. Так же надо добавить процедуру(ы) "индексирования" массивов (быстрое упорядочивание массива поколения с удалением дубликатов, или даже вставки в уже упорядоченный набор (без вставки дублей). Тогда разрастания массива за счет множественности вхождений не потребуется.


2. Возлагать отбрасывание повторных вхождений потомков на уровень на Jet - за счет уникального индекса (потомок, уровень) - для нерекурсиной процедуры вряд ли имеет смысл (если только не заменять процедуру заполнение массива текущего уровня чтением из таблицы). И я не уверен, что проверка уникальности на большой таблице (т.е. с чтением индекса) будет быстрее (таких же) методов быстрого поиска, но внутри исключительно (!уже) размещенного в памяти массива.
Однако подкупает простота реализации. Попробуйте. (Не надо передирать методов быстрого поиска/сортировки/вставки_в_сортированный_список из каких - нить букварей - все реализовано в движке jet).
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32510472
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
итак, не входя в сортировку массивов, добавляем потомкам уникальные индексы (iGen,Childe) и наоборот + правим рекурсивные процедуры (по крайней мере "моя" StartT(7) - прогонка по рекордсету начинает завершаться в разумное время -222718 потомков(с вероятностью нескольки вхождений на РАзные уровни), из них 36874 уникальных. (а сл-но, петель таки нет).

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
Option Compare Database
Option Explicit
  Private dbs As Database, rstDesc As Recordset, rstS As Recordset, rstD As Recordset
  
Sub start(id As Long)
    Set dbs = CurrentDb
    dbs.Execute ("Delete From потомки")
    Set rstDesc = dbs.OpenRecordset("потомки")
    FindDescendant id,  1  '29, 1
    rstDesc.Close
    Set rstDesc = Nothing
End Sub


Sub FindDescendant(id As Long, iGeneration As Long)
    
    Dim i As Long, rst As Recordset, n As Long
    Set rst = dbs.OpenRecordset("SELECT ребенок FROM семьи LEFT JOIN дети ON семьи.id=дети.семья WHERE Not ребенок Is Null AND (муж=" & id & " OR жена=" & id & ")")
    With rst
        Do While Not .EOF
            n = .Fields(0)
            With rstDesc
                On Error Resume Next
                .AddNew
                .Fields(0) = n
                .Fields(1) = iGeneration
                .Update
            End With
            If Err = 0 Then
                i = iGeneration + 1
                FindDescendant .Fields(0), i
            End If
            On Error GoTo 0
            .MoveNext
        Loop
    End With
    rst.Close
    Set rst = Nothing
End Sub

Sub startT(id As Long)
    Set dbs = CurrentDb
    dbs.Execute ("Delete From потомки")
    Set rstDesc = dbs.OpenRecordset("потомки")
    Set rstS = dbs.OpenRecordset("семьи", dbOpenTable)
    Set rstD = dbs.OpenRecordset("дети", dbOpenTable)
    rstD.Index = "СемьяРебенок"
    FindDescendantT id, 1 '29,  1 
    rstDesc.Close
    Set rstDesc = Nothing
    rstS.Close
    Set rstS = Nothing
    rstD.Close
    Set rstD = Nothing
End Sub
Sub FindDescendantT(id As Long, iGeneration As Long)
    Dim i As Long, nS As Long, nR As Long, iSx As Long
    Dim sIn( 0  To  1 ) As String
    
    sIn( 0 ) = "Мid": sIn( 1 ) = "Жid"
    For iSx =  0  To  1 
        With rstS
            .Index = sIn(iSx)
            .Seek ">=", id,  0 
            If Not .NoMatch Then
                Do While .Fields(iSx +  1 ) = id
                    nS = .Fields("id")
                    With rstD
                        .Seek ">=", nS,  0 
                        If Not rstD.NoMatch Then
                            Do While .Fields("Семья") = nS
                                nR = .Fields("Ребенок")
                                With rstDesc
                                    On Error Resume Next
                                    .AddNew
                                    .Fields( 0 ) = nR
                                    .Fields( 1 ) = iGeneration
                                    .Update
                                End With
                                If Err =  0  Then
                                    i = iGeneration +  1 
                                    FindDescendantT nR, i
                                    .Seek ">", nS, nR
                                Else
                                    .MoveNext
                                End If
                                On Error GoTo  0 
                                If .NoMatch Or .EOF Then Exit Do
                            Loop
                        End If
                    End With
                    .Index = sIn(iSx) 'мог смениться
                    .Seek ">", id, nS
                    If .NoMatch Then Exit Do
                Loop
            End If
        End With
    Next iSx
End Sub
при этом (запрет повторного вхождения потомка в уровень) имеем:
Код: plaintext
1.
2.
3.
4.
5.
6.
Ребенок	Dlt	MaxG	MinG	Cnt
 29014 	 17 	 43 	 26 	 18 
 33567 	 17 	 43 	 26 	 18 
 33568 	 17 	 43 	 26 	 18 
 27295 	 17 	 43 	 26 	 18 
 33563 	 17 	 43 	 26 	 18 
 17191 	 17 	 42 	 25 	 18 
поражает, насколько одна линия успела обогнать (по числу поколений) другую - 26/18 - в 1.5 раза! (быстрее плодились).
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32510528
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
и напоследок времена
(все модифицировано аналогично)
запускаем подряд:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
startM( 7 )
  52 . 7035000000033  
startT( 7 )
  71 . 4063749999987  
startA( 7 )
  46 . 2032499999987  
startM( 7 )
  54 . 4381250000006  
видимо подросла база ( 52 . 7  -  54 . 4 )
после сжатия:
startA( 7 )
  42 . 8756250000006  
фсе. (Пока рисовать вставку уникумов в отсортированные массивы не буду - надо бы и поработать (труба зовет). Но, поскольку задачка сродни любой иерархической (справочники/каталоги и т.п.), то попозже посмотрю - имеет не токмо факультативный интерес.

удач. С праздничком.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32510562
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф/assa
Супер!
Для Рюрика (40436) ищет 33886 потомков за 5 сек!
авторНо, поскольку задачка сродни любой иерархической (справочники/каталоги и т.п.), то попозже посмотрю - имеет не токмо факультативный интерес.
Не забудьте и про поиск предков :)
Спасибо и с наступающим праздником!

З.Ы. Для №29 находит 33046 потомков,а по упомянутой выше программе 33047.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32511348
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Постскриптум предыдущего сообщения ошибочен!
Там к потомкам добавляется и сама персона.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32511954
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Еще одна заморочка :(
В таблице нужно поле parent.
Добавляем в код
Код: plaintext
       .Fields( 2 ) = id
Представлять таблицу нужно в следующем виде:
Код: plaintext
1.
2.
SELECT потомки.id
FROM (потомки LEFT JOIN дети ON потомки.id = дети.ребенок) LEFT JOIN дети AS дети_1 ON потомки.parent = дети_1.ребенок
ORDER BY потомки.generation, дети_1.счетчик, дети.счетчик
На этом порядке сортировки строится новая нумерация записей начиная с 1.
Нужно заменить поле parent в соответствии с новой нумерацией.
Делаю так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
Public Function NewNumber(id)
    With rst
        .FindFirst "id=" & id
        NewNumber = .AbsolutePosition +  1 
    End With
End Function

Public Sub NumberParent()
    Set dbs = CurrentDb
    Set rst = dbs.OpenRecordset("SELECT потомки.id FROM (потомки LEFT JOIN дети ON потомки.id = дети.ребенок) LEFT JOIN дети AS дети_1 ON потомки.parent = дети_1.ребенок ORDER BY потомки.generation, дети_1.счетчик, дети.счетчик;")
    DoCmd.RunSQL "UPDATE (потомки LEFT JOIN дети ON потомки.id = дети.ребенок) LEFT JOIN дети AS дети_1 ON потомки.parent = дети_1.ребенок SET потомки.parent = NewNumber(parent);"
End Sub
Но это слишком долго: более 3-х мин.
Может есть лучшее решение?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32512483
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что-то я зарапортовался в последнем посте.
Правильная последовательность в детях (которая определена в таблице "дети" по счетчику) нарушается при создании таблицы "потомки", т.к. сортировка производится по индексу "СемьяРебенок".
Это касается и последовательности семей. Нужно в таблицу "семьи" добавить счетчик и сортировку проводить с его участием.
В случае, когда более одного брака, нужна привязка ребенка к номеру брака.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32512576
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вообщем, последовательность записей для 40436 д.б. такой:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
№ п/п	№ родителя	№ брака		№ персоны	         № поколения	

1					40436		1		Рюрик РУССКИЙ
2	1				40440		2		Игорь Рюрикович РЮРИКОВИЧ
3	1				4		2		Олег Младший ЛАДОЖСКИЙ
4	2				7		3		Святослав Игоревич РЮРИКОВИЧ
5	3				6		3		Игорь Младший ЛАДОЖСКИЙ
6	4		1 		9		3		Ярополк Святославич РЮРИКОВИЧ
7	4		1 		10		3		Олег Святославич ДРЕВЛЯНСКИЙ
8	4		1 		11		3		Олег Святославич РЮРИКОВИЧ
9	4		2 		13		3		Владимир Святославич РЮРИКОВИЧ
10	5				5428		3		Улеб ЛАДОЖСКИЙ
11	5				5429		3		Слуды ЛАДОЖСКИЙ
Было бы здорово, чтобы сразу получать такую таблицу потомков!
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32512978
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Гы. А я сразу понял, что вам никакая рекурсия на..фих не нужна. Вам нужен эффективный механизм построения выборок из почти статических данных в аксесс (т.е. в системе, не поддерживающей запросы иерархического вида /вроде в оракле что-то есть)).

Тогда вам, видимо, надо построить "индексную таблицу". Такую, из которой все последующие вещи считаются простыми запросами (наборы полей связи для всех мыслимых запросов проиндексировать). Поскольку первичные данные меняются редко, то и перестройка вспомогательной таблицы должна проводиться не каждый раз, а только при изменении, причем перестройка не всей таблицы, а только конкретного участка.
__________

Нумеровать "логический" порядок счетчиками – гнилое дело. Да и для семей в счетчике может крыться проблема. Добавьте поля "физическая очередность брака" для каждой из персон (тут в общем счетчике возможна масса логических казусов, особо для активных единовременных многоженцев, повторных браков со старым партнером и т.п., боюсь, возможен и некоторый "релятивизм", когда один порядок потребуется для одного партнера, другой – для другого. А поле-то общее. Некой экономии, кажется, можно добиться объявив поля меньшей длинны – например - как байтовые, но идущие физически друг за другом).

____
PS
Если вы хотите модифицировать способ хранения данных – 3 минуты - не проблема. (Продумайте один раз способ хранения и время от времени (по изменении данных) перестраивайте вспомогательные структуры. Если же нужна именно выборка – не делайте UPDATE (дисковая операция), просто верните NewNumber(parent) (и т.п. – если нужно выводить несколько значений, - при первом обращении к функции заполните _коллекцию_, с индексом (key) элементов cStr( id) (id – старый id предка), простым MoveNext (а не Find!!! – что много быстрее, тогда и набор можете открыть только для прямого прохода) при повторных вызовах дергайте члены из коллекции по id , представляется, для коллекции васиком должно строиться что-то типа индекса в памяти по key – что много ускоряет поиск, если я ошибаюсь (в догадках) - получите тот же результат, что и Find-ом (еще и память похерите зря)).
А rst, по любому, открывайте как статический набор.

___
ЗЫ ( к "нерекурсивной процедуре):
(кстати, переприсваивать массивы потомков из "следующих" в "текущие" не обязательно. Надо разветвить процедуру для четных/нечетных поколений. (можно и простым копи/пастом). Одно из "изячных" решений – объявить тип "поколение" содержащий массив поколения, и объявить массив p(0 To 1) из двух поколений – на уровне модуля pC==p(iG mod 2); pN==p((iG+1) mod 2)), а "ветвить" не код а просто за счет подстановки нужных индексов при четном/нечетном поколении менять поколение – источник и поколение – адресат..
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32513018
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2фыыф
авторТогда вам, видимо, надо построить "индексную таблицу". Такую, из которой все последующие вещи считаются простыми запросами (наборы полей связи для всех мыслимых запросов проиндексировать).
Можно какой-нибудь пример?
И еще вопрос: что означает "0" в выражении
Код: plaintext
.Seek ">=", id,  0 
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32513139
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
вот ваша табличка потомков и есть вспомогательная, если добавить id семьи, есс-но (и не надо ее перестраивать по запросу, а только по изменению данных удалять не все, а только "ветку" от этой семьи удалить/вставить).
чтобы таблица была удобна для шустрых выборок, нужны соответствующие индексы (id,ребенок) - он и так видимо ключ (или могабыть (id,уровень,ребенок) - если учитываете все сепени родства по всем линиям - тут надо подумать над оптимальным порядком полей (уровень,ребенок) - чтобы не строить лишних индексов) - будут пользоваться в запросах на потомков id; (ребенок,уровень,id) - // - в запросах на предков ребенка, (ну, посмотрите, как у вас строятся запросы, так и индексы составные подберите).

И будет это все зело огромным, но за счет индексов выборки будут строиться быстро. Причем чем индексов больше, тем цена вставки и редактирования выше. Но если данные почти не меняются (таблица не переписывается целиком), то основной минус - объем базы. И время восстановления/сжатия (при сжатии аксесс, кажется, перестраивает индексы целиком).


:) Да, наткнулся я тут, образовываясь, на тип индексов "битовые карты" - там составные индексы не нужны. ибо эти карты, кажется аддитивны (как средства поиска) поиск по составному индексу - просто на лету производимая комбинация поиска по простым. (не копал, надо посмотреть). Но, к сожалению, в аксессе их нет.


______
0- просто второе поле поиска индекса
пишите при первом вызове
.Seek ">=", id
- в данном случае это не важно (ребенок>=0, not null)
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32515654
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
После долгих раздумин, определил структуру таблицы "потомки" для правильной ее сортировки:
Код: plaintext
1.
2.
3.
4.
id		персона
generation	поколение
parent		предок
orderPerson	номер персоны в семье
orderParent	номер предка в семье его родителей
Определение первы 4 полей в функции FindDescendantsТ понятно.
Для получения orderPehson в функцию нужно включить третий аргумент, определяемый из поля "счетчик" таблицы "дети" для предка в семье его родителей. С первым вызовом все понятно, а дальше ничего не смог придумать :(
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
Sub startT()
    Set dbs = CurrentDb
    dbs.Execute ("Delete From потомки")
    Set rstDesc = dbs.OpenRecordset("потомки")
    Set rstS = dbs.OpenRecordset("семьи", dbOpenTable)
    Set rstD = dbs.OpenRecordset("дети", dbOpenTable)
    rstD.Index = "СемьяРебенок"
    FindDescendantT  1 ,  1 ,  1 
    rstDesc.Close
    Set rstDesc = Nothing
    rstS.Close
    Set rstS = Nothing
    rstD.Close
    Set rstD = Nothing
End Sub
Sub FindDescendantT(id As Long, iGeneration As Long, iParent As Long)
    Dim i As Long, nS As Long, nR As Long, iSx As Long
    Dim sIn( 0  To  1 ) As String
    sIn( 0 ) = "Мid": sIn( 1 ) = "Жid"
    For iSx =  0  To  1 
        With rstS
            .Index = sIn(iSx)
            .Seek ">=", id,  0 
            If Not .NoMatch Then
                Do While .Fields(iSx +  1 ) = id
                    nS = .Fields("id")
                    With rstD
                        .Seek ">=", nS,  0 
                        If Not rstD.NoMatch Then
                            Do While .Fields("Семья") = nS
                                nR = .Fields("Ребенок")
                                With rstDesc
                                    On Error Resume Next
                                    .AddNew
                                    .Fields( 0 ) = nR
                                    .Fields( 1 ) = iGeneration
                                    .Fields( 2 ) = id
                                    .Fields( 3 ) = rstD.Fields("счетчик")
                                    .Fields( 4 ) = iParent
                                    .Update
                                End With
                                If Err =  0  Then
                                    i = iGeneration +  1 
                                    FindDescendantT nR, i, ? ' не могу понять, как задать аргумент
                                    .Seek ">", nS, nR
                                Else
                                    .MoveNext
                                End If
                                On Error GoTo  0 
                                If .NoMatch Or .EOF Then Exit Do
                            Loop
                        End If
                    End With
                    .Index = sIn(iSx)
                    .Seek ">", id, nS
                    If .NoMatch Then Exit Do
                Loop
            End If
        End With
    Next iSx
End Sub
Не поможете?
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32515961
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
1. для ПРАВИЛЬНОГО получения номера поколения по КРАТЧАЙШЕЙ ЛИНИИ надо таки отказаться от иерархического вызова (пишет первое найденное вхождение потомка, по первой попавшейся линии). Или дополнить (в случае Err в .Add проверкой записанного и текущего (в рекурсивной процедуре) поколения, а при необходимости и .Edit (номер поколения, и генетические веса, если потребуется).

2. НАстоятельно рекомендую не завязываться на id предка но на id семьи (вдвое снизит объем таблицы, запросы будут более прозрачными логически). Но если вы склоняетесь не к постоянно заполненной (редко обновляемой) таблице, то возможно имеет смысл делать как сочтете нужным.

3. не совсем понимаю, что такое "номер персоны в семье" и на кой он нужен (внутри поколения нумерация вообще произвольна). Но такого рода нумерация легко производится в нерекурсивной (последовательный перебор по поколениям) процедуре.

______
для "постоянно заполненной таблицы транзиктивных связей" примерно следующая структура:

id персона
pid семья предков (соотв уровня)
generation поколение (уровень наследования)
weght вес (семьи предков) в генетическом наследстве, Double
/* (степень родства суммарно по всем линиям) */

при этом семья:
id
муж
жена
nмуж № брака, байт
nжена № брака, байт

дети - как есть
Семья
Ребенок
/* счетчик в вашей структуре лишний == Ребенок*/

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


хотя для семей возможно лучше разбить таблицы:
семья:
(уникум, служит для организации связей с потомками и супругами)
id -PKey
супруги:
id - Fkey семья(id)
idp - персона Fkey дети (
sx - роль в семье, boolean
nсемьи - номер брака

В таком виде данных в семье/супруги/дети более чем достаточно для первичного расчета таблицы связей "потомки", а полного набора таблиц с (учетом последней таблицы) - для формирования практически за счет одного SQL всех возможных отчетов. Если же вы настаиваете на нумерации внутри "линии", то это заведомо относительное (отсчитывается от произвольно выбранного предка) поле можно расчитывать динамически (как я писал - заполняя коллекцию или массив) при выводе отчетов, не перестраивая таблицу "потомков".

__________
ЗЫ - Если затруднились переформировать нерекурсивную разновидность процедуры, то сейчас поищу...
вот, с какими-то лишними наворотами:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
Option Compare Database
Option Explicit
Private dbs As Database, rstDesc As Recordset, rstS( 0  To  1 ) As Recordset, rstD As Recordset ', n As Long
Private pC() As Long, pN() As Long

Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)


Sub startA(id As Long, Optional bMod As Boolean)
    Dim iSx As Long
    Dim sIn(0 To 1) As String
Dim Start_t As Double
    Start_t = Timer
    Set dbs = CurrentDb
    dbs.Execute ("Delete From потомки")
    Set rstDesc = dbs.OpenRecordset("потомки")
    
    sIn(0) = "Мid": sIn(1) = "Жid"
    For iSx = 0 To 1
        Set rstS(iSx) = dbs.OpenRecordset("семьи", dbOpenTable)
        rstS(iSx).Index = sIn(iSx)
    Next iSx

    Set rstD = dbs.OpenRecordset("дети", dbOpenTable)
    rstD.Index = "СемьяРебенок"
    FindDescendantAll id, 1, bMod '29,  1 
    rstDesc.Close
    Set rstDesc = Nothing
    For iSx =  0  To  1 
        rstS(iSx).Close
        Set rstS(iSx) = Nothing
    Next iSx
    rstD.Close
    Set rstD = Nothing
    Debug.Print Timer - Start_t
End Sub

Sub FindDescendantAll(id As Long, iGeneration As Long, Optional bMod As Boolean)
Dim nP As Long, nC As Long, iG As Long, bF As Boolean
Dim iC As Long

    'On Error Resume Next
    bF = FindDescendantA(id, iGeneration)   'первый вызов
    iG = iGeneration
    Do While bF  'цикл по поколениям
        'переместим следующих в текущий
        Erase pC
        ReDim pC( 0  To UBoundE(pN))
        If bMod Then
            'сдвиг указателей
            'CopyMemory pC( 0 ), pN( 0 ), x * (UBound(pN) +  1 )
            'где x - количество байт в элементе массива - для инт - 2 для лонга 4
            CopyMemory pC(0), pN(0), 4 * (UBoundE(pN) + 1)
        Else
            For iC = 0 To UBound(pN)
                pC(iC) = pN(iC)
            Next iC
        End If
        Erase pN    'очистка следующего
        bF = False
        iG = iG +  1 
        For nC =  0  To UBound(pC)
            bF = FindDescendantA(pC(nC), iG) Or bF
        Next nC
    Loop
End Sub

Function UBoundE(Ar As Variant) As Long
    On Error Resume Next
    UBoundE = UBound(Ar)
    If Err <>  0  Then UBoundE = - 1 
End Function

Function FindDescendantA(id As Long, iGeneration As Long) As Boolean
    Dim i As Long, nS As Long, nR As Long, iSx As Long
    Dim kN As Long
    
    For iSx =  0  To  1 
        With rstS(iSx)
            '.Index = sIn(iSx)
            .Seek ">=", id, 0
            If Not .NoMatch Then
                Do While .Fields(iSx + 1) = id
                    nS = .Fields("id")
                    With rstD
                        .Seek ">=", nS ',  0 
                        If Not rstD.NoMatch Then
                            Do While .Fields("Семья") = nS
                                nR = .Fields("Ребенок")
                                With rstDesc
                                    On Error Resume Next
                                    .AddNew
                                    .Fields( 0 ) = nR
                                    .Fields( 1 ) = iGeneration
                                    .Update
                                End With
                                If Err =  0  Then
                                    i = iGeneration +  1 
                                    FindDescendantA = True 'есть хоть один
                                    kN = UBoundE(pN) + 1
                                    ReDim Preserve pN(0 To kN)
                                    pN(kN) = nR 'вызовем потом
                                Else
                                End If
                                On Error GoTo  0 
                                .MoveNext
                                If .NoMatch Or .EOF Then Exit Do
                            Loop
                        End If
                    End With
                    '.Seek ">", id, nS
                    .MoveNext
                    If .NoMatch Or .EOF Then Exit Do
                Loop
            End If
        End With
    Next iSx
End Function
- это без учета рекомендованных изменений структуры. (Ваша проблема со счетчиками номера персоны в линии решается в данной процедуре вводом одной переменной уровня модуля, навариваемой на 1-ку при успешном добавлении записи).



и я б еще поэкспериментировал с поиском в большой коллекции по "key". если окажется быстрее, чем выборка из массива перебором по значению (или модификаций с вставкой в упорядоченные массивы - с "раздвижкой", что долго), то легко решается проблема пересчета генетического веса без вызова .edit при повторном нахождении (на этапе прохода по поколению результаты грузятся в коллекцию записей с инедексом str(id) (определенный пользователем тип, вес в поколении просто пересчитывается, при ошибке добавления по ключу), а по проходу все поколение записывается из коллекции в таблицу (add or edit ранее вставленных записей). Но это именно в случае желания иметь степень генетического родства с учетом множественности линий наследования. В конце-концов может оказаться что даже вся ваша табла "потомков" шустро влезет в такую коллекцию в разумный объем памяти (у вас что-то до 40000 "записей" длиной 8 байт, +, если я праильно соображаю на счет конструкции "коллекций" и их "индексов", структурка будет более рыхлой, чем массив (записей) на некий множитель, не больший, видимо, 5-10 (вроде как даже таблички не более чем в 5 раз более рыхлы, чем плоские файлы), и ваша коллекция записей (для одного предка) влезет в 1.6 -3.2 мегабайта. Что уже интересно с точки зрения переноса логики связи не на таблицу потомков, а на функцию(и) связей, рботающую с такими массивами по предложенной ранее схеме...
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32516098
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
автор3. не совсем понимаю, что такое "номер персоны в семье" и на кой он нужен (внутри поколения нумерация вообще произвольна). Но такого рода нумерация легко производится в нерекурсивной (последовательный перебор по поколениям) процедуре.
Внутри поколения нумерация д.б. не произвольна!
Потомков нужно показывать по старшинству предков.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32516625
фыыф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
а где вы возьмете старшинство внутри одной семьи (старшинство предков-то тут одинаково)?
а то у вас в таблицах старшинства детей в семье и нет [:0)
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32516724
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 фыыф
авторв таблицах старшинства детей в семье и нет [:0)
Есть - это счетчик. Дети в каждой семье записаны уже в нужном порядке.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32517024
я так и думал, что применено какое-нить мм... решение. :0)

постройте индекс "новый" по "детям" ==(семья,счетчик, ребенок) вместо (Семья,ребенок)
и бегайте по этому индексу. (замените на rstD.Index ="новый")

к тому ж в неиерархическом случае Seek у вас используется только во входе (".=", id).

Внутри семьи потомки будут перебираться в порядке "счетчика", вот в этом порядке и наваривайте ваше поле старшинства по всей иерархии.

----
или, чтобы не переписывать:
обновите мужей/жен в семьях на значение "счетчик" из детей
затем "ребенков" в "детях" на (то же) значение "счетчик"
(после чего поле счетчика можете грохнуть за ненадобностью,
и ввести нормальное поле для учета порядка в семьях)
(Семья,ребенок) станут упорядочены внутри семей по старшинству детей.
...
Рейтинг: 0 / 0
Иерархия и рекурсия
    #32517086
Sergey_New
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторобновите мужей/жен в семьях на значение "счетчик" из детей
затем "ребенков" в "детях" на (то же) значение "счетчик"
(после чего поле счетчика можете грохнуть за ненадобностью,
и ввести нормальное поле для учета порядка в семьях)
(Семья,ребенок) станут упорядочены внутри семей по старшинству детей.
Вот этого я и добиваюсь, пока безуспешно :(
Знаю что нужно, не знаю как...
...
Рейтинг: 0 / 0
120 сообщений из 120, показаны все 5 страниц
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / Иерархия и рекурсия
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]