powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / Иерархия и рекурсия
25 сообщений из 120, страница 2 из 5
Иерархия и рекурсия
    #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
25 сообщений из 120, страница 2 из 5
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / Иерархия и рекурсия
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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