Rambler's Top100
Форум: MS ACCESSVBVBA MS OfficeMS SQL server
Новые сообщения: 0000

Форум: MS ACCESS

Вопросы связанные с MS ACCESS

Обновить визитку
Участники «Online»
Все участники

 
 

Доброго времени суток, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Создание запроса для поиска предков
 
 автор: Pasat   (07.08.2008 в 10:33)   личное сообщение
12 Кб.
 
 

Хорошего утра ВСЕМ
Скажите пожалуйста
Возможно ли получить запрос выводящий всех предков (если они есть) для каждой записи в древовидной структуре данных, а именно имеем таблицу «Departments» с 3-мя полями (DepID, ParentID, Name1) со след.записями
DepID ParentID Name1
1 0 A
2 1 B1
3 1 B2
4 2 C1
5 3 C2
6 3 C3

Нужно найти всех предков (если они есть) для каждой записи, т.е. получить такой запрос
DepID ancestorID
2 1
3 1
4 1
4 2
5 1
5 3
6 1
6 3
Где
DepID=2 имеет одного предка с DepID=1
DepID=4 имеет двух предков с DepID=1, DepID=2

Ну и так далее

С уважением ПАСАТ

  Ответить  
 
 автор: FORMAT   (07.08.2008 в 10:53)   личное сообщение
 
 

А что у вас показывает ParentID?

  Ответить  
 
 автор: Pasat   (07.08.2008 в 11:05)   личное сообщение
 
 

Если правильно понял вопрос, то
ParentID показывает ID записи из таблицы «Departments»
т.е. имеем дерево

A имеет детей В1 и В2
В1 имеет детей С1
В2 имеет детей С1 и С2

  Ответить  
 
 автор: Pasat   (07.08.2008 в 11:21)   личное сообщение
 
 

сорри

A имеет детей В1 и В2
В1 имеет детей С1
В2 имеет детей С2 и С3

  Ответить  
 
 автор: FORMAT   (07.08.2008 в 11:44)   личное сообщение
 
 

По моему это таблицу нужно разбить на 2 таблицы и от туда уже вытягивать данные.

  Ответить  
 
 автор: Pasat   (07.08.2008 в 12:05)   личное сообщение
 
 

Я поэтому и спросил
Если есть возможность создать запрос то зачем тогда таблица
Вопрос в том как его создать???
и (или)
возможно ли его создать ???

  Ответить  
 
 автор: Pasat   (08.08.2008 в 12:22)   личное сообщение
 
 

...

  Ответить  
 
 автор: Pasat   (11.08.2008 в 12:38)   личное сообщение
 
 

С возвращением OSMOR

Что Вы думаете:

возможно ли создать такой запрос ???

  Ответить  
 
 автор: osmor   (11.08.2008 в 16:08)   личное сообщение
 
 

спасибо.
надо внимательно вопрос почитать... разгребу работу - посмотрю

  Ответить  
 
 автор: osmor   (11.08.2008 в 18:23)   личное сообщение
 
 

решение в лоб:

SELECT DepID, ParentID  as ancestorID
FROM Departments
WHERE (((Departments.ParentID)<>0))
Union ALL
SELECT D.DepID, D1.ParentId as ancestorID
FROM Departments as D , Departments AS D1
WHERE  D.ParentId = D1.DepID and  D1.ParentID<>0
Union ALL
SELECT D.DepID, D2.ParentId as ancestorID
FROM Departments as D , Departments AS D1,Departments as D2
WHERE  D.ParentId = D1.DepID and  D1.ParentID = D2.DepID and D2.ParentID<>0
Order by DepId, ancestorID DESC

Union должно быть столько сколько возможно уровней -1 , для данного набора достаточно было бы 1 Union т.е.

SELECT DepID, ParentID  as ancestorID
FROM Departments
WHERE (((Departments.ParentID)<>0))
Union ALL
SELECT D.DepID, D1.ParentId as ancestorID
FROM Departments as D , Departments AS D1
WHERE  D.ParentId = D1.DepID and  D1.ParentID<>0
Order by DepId, ancestorID DESC

  Ответить  
 
 автор: Pasat   (12.08.2008 в 08:14)   личное сообщение
 
 

СУПЕР – большое спасибо
Если я все правильно понял - это подойдет если используется определенное кол-во уровней не больше того которого мы напишем в запросе (половина задачи решена – можно сделать 5, 10, 20 … union all по аналогии).

А что делать если у нас будет неограниченное (бесконечное) количество уровней вложенности ???
Ведь иерархическая (древовидная) структура данных это предполагает

  Ответить  
 
 автор: osmor   (12.08.2008 в 08:40)   личное сообщение
 
 

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

  Ответить  
 
 автор: Pasat   (12.08.2008 в 10:07)   личное сообщение
 
 

Если мы имеем основную таблицу «Departments» с 3-мя полями (DepID, ParentID, Name1) - в ней хранится иерархическая структура данных, где Поле ParentID является ссылкой на Id (первичный ключ) вышестоящего уровня в иерархии - со след.записями
DepID ParentID Name1
1 0 A
2 1 B1
3 1 B2
4 2 C1
5 3 C2
6 3 C3

и вспомогательную таблицу ANCESTORS содержащую всего два поля. В одном из них храним Id элемента, а в другом - Id всех его предков (Поле ancestorID ссылается на Id предка каждого элемента. В данном случае оно позволяет узнать все подразделения, в которые входит данный элемент)
DepID ancestorID
2 1
3 1
4 1
4 2
5 1
5 3
6 1
6 3

То подобная схема легко позволяет получить любую информацию об иерархических элементах одним запросом
1) можно получить всех предков, либо потомков определенного элемента (нет необходимости добавлятть поле FullPath ,в которое через разделитель записывать все коды от корня до данной ветки)
2) можно узнать, на каком уровне иерархии находится элемент (получив в запросе количество его предков)
3) можно узнать, отсутствуют или имеются другие элементы, входящие в конкретный элемент
Пользуясь двумя такими таблицами, можно легко строить практически любые запросы, характерные для иерархических объектов

Вот я и озадачился тем чтобы иметь только одну таблицу «Departments» а вместо вспомогательной таблицы ANCESTORS использовать запрос (вроде все данные в таблице «Departments» для этого есть).

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

Что Вы посоветуете в данном случае делать ???
Или рациональнее все-таки иметь постоянную вспомогательную таблицу ???

И последниий вопрос
Является ли вообще обтимальным выбранное решение, а именно использывание двух таблиц «Departments» и «ANCESTORS» для работы с иерархической структурой данных. Если есть что-либо более простое, тогда все выше описанное просто не нужно

С уважением ПАСАТ

  Ответить  
 
 автор: osmor   (12.08.2008 в 10:31)   личное сообщение
 
 

если бы знать что является оптимальным... все зависит от задач, во многих случаях нужно только дерево без всяких "всех родителей и всех потомков"
в свете вышесказанного таблица ANCESTORS мне кажется наиболее привлекательным решением, только пока не понял как поддерживать ее актуальность при перетаскивании веток...

  Ответить  
 
 автор: Pasat   (12.08.2008 в 10:49)   личное сообщение
 
 


как поддерживать ее актуальность при перетаскивании веток


Вроде бы пока перетаскивать ветки не требуется

  Ответить  
 
 автор: ГлазастыйМышь   (12.08.2008 в 12:03)   личное сообщение
 
 

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

Public Function GetParent(Id As Double) As String
    Dim prom As Double
On Error GoTo ErrDebug
    
    prom = Nz(DLookup("ParentID", "Departments", "DepID =" & Id), 0)
    
    If prom > 0 Then
        GetParent = "|" & prom & GetParent(prom)
    End If
ExitHere:
    Exit Function
ErrDebug:
    Resume ExitHere
End Function


тогда запрос будет иметь вид

SELECT q.DepID, w.DepID
FROM Departments AS q, Departments AS w
WHERE (((InStr("|" & [q].[ParentID] & GetParent([q].[parentid]) & "|","|" & [w].[depid] & "|"))>0))
ORDER BY q.DepID, w.DepID DESC

  Ответить  
 
 автор: Pasat   (12.08.2008 в 13:01)   личное сообщение
 
 

Пока не понял как это работает
но главное РАБОТАЕТ...
ОГРОМНОЕ СПАСИБО

как вариант, но не очень красивый 

почему ???

надо смотреть как будет себя вести при большом количестве веток

а как может быть ???

Успел немного потестировать вроде все коректно, только притормаживает при большом количестве записей


  Ответить  
 
 автор: ГлазастыйМышь   (12.08.2008 в 13:28)   личное сообщение
 
 

некрасивый - потому что постоянно пользуется dlookup для каждого узла, причем может неоднократно

про то и говорил, что на больших объемах будет притормаживать
суть метода: рекурчивная функция, в результате выдает для каждого узла список их родителей разделенный знаком |
ну а дальше нечеткое связывание таблицы с самой собой, по вхождению узла в список родителей

  Ответить  
 
 автор: Pasat   (12.08.2008 в 13:39)   личное сообщение
 
 

Как Вы думаете возможно ли придумать что-либо более быстрое ???
Если да, то где рыть ???

зы быстрейшего выздоровления

  Ответить  
 
 автор: ГлазастыйМышь   (12.08.2008 в 16:17)   личное сообщение
 
 

может быть стоит попробывать бегать по открытому рекордсету поиском и результаты укладывать в массив, который выложить потом к Excell (либо сразу результаты в Excell выводить)

  Ответить  
 
 автор: KrukVN   (12.08.2008 в 18:38)   личное сообщение
70 Кб.
 
 

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

  Ответить  
 
 автор: Pasat   (12.08.2008 в 19:55)   личное сообщение
 
 

Делали так ???

бегать по открытому рекордсету поиском и результаты укладывать в массив, который выложить потом к Excell (либо сразу результаты в Excell выводить)


Мне кажется Excell здесь не нужен ???

  Ответить  
 
 автор: час   (12.08.2008 в 20:39)   личное сообщение
 
 

намудохался.. что за выражение........
Видимо Вы прсто Зае...сь с решением проблеммы .

  Ответить  
 
 автор: KrukVN   (12.08.2008 в 23:24)   личное сообщение
18 Кб.
 
 


Видимо Вы прсто Зае...сь с решением проблеммы   .

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

  Ответить  
 
 автор: osmor   (13.08.2008 в 08:46)   личное сообщение
 
 

"osmor здесь как-то выкладывал для тестирования dll-ку, а исходников не дал "
есть такое дело, я ее доделал
http://hiprog.com/index.php?option=com_content&task=view&id=251661568&Itemid=35
исходников пока не дам...
Ну там все просто, там нет запросов, бегу по дереву, читаю ноды

  Ответить  
 
 автор: Скорп   (12.08.2008 в 23:27)   личное сообщение
 
 

ужас!!

  Ответить  
 
 автор: Vik   (16.08.2008 в 20:36)   личное сообщение
 
 

В свое время была похожая задачка. Таблица административных единиц KOATUU (область/район/сельсовет/населеный пункт) отображалась через TreeViev.
При выборе любой админединицы необходимо было отобразить информацию по всех входящив в нее "детях".
Решил следующим образом:
1. Таблицу дополнил полем Cheked (Boolean) для меток выделенных записей, которое в начале равно Fаlse.
2. При выделении узла поле Cheked этой записи получает значение True.
3. Дальше выполнялся через .Execute запрос на обновление, который менял Cheked на True для всех записей, являющихся дочерними (в Вашем случае - родительскими) относительно записей, в которых Cheked = True.
4. Execute повторно выполняется до того времени, пока количество обновленных записей (.RecordsAffected) > 0 .
5. В результате быстро, качественно и недорого в таблице все необходимые Вам записи имеют Cheked = True.


    strSQL1 = "UPDATE Koatuu SET Koatuu.Checked = True " _
    & "WHERE ((Koatuu.Key) = '" & CurKey & "');"
    
    strSQL2 = "UPDATE Koatuu SET Koatuu.Checked = True " _
    & "WHERE (((Koatuu.Checked)=False) AND ((Koatuu.Parent) " _
    & " In (SELECT Koatuu.Key FROM Koatuu WHERE (((Koatuu.Checked)=True)))));"

    Set qdf = dbs.QueryDefs("Temp")
    qdf.SQL = strSQL1
    qdf.Execute
            
    qdf.SQL = strSQL2
    
Do
    DoCmd.SetWarnings False
        qdf.Execute
    DoCmd.SetWarnings True
Loop While qdf.RecordsAffected > 0

  Ответить  
 
 автор: Pasat   (18.08.2008 в 11:38)   личное сообщение
19 Кб.
 
 

Спасибо Vik
Предложенное Вами решение работоспособно и может пригодиться для решения некоторых задач (если кому надо см.аттач.)

Люди если есть еще идеи буду благодарен
Задача такая
На основе таблицы Departments получить запрос с записями как в таблице TasksResults
(см.аттач.)

Один из вариантов уже предложил ГлазастыйМышь
как вариант, но не очень красивый (плюс надо смотреть как будет себя вести при большом количестве веток) создать функцию

Public Function GetParent(Id As Double) As String 
    Dim prom As Double 

    prom = Nz(DLookup("ParentID", "Departments", "DepID =" & Id), 0) 
     
    If prom > 0 Then 
        GetParent = "|" & prom & GetParent(prom) 
    End If 
End Function 

тогда запрос будет иметь вид

SELECT q.DepID, w.DepID 
FROM Departments AS q, Departments AS w 
WHERE (((InStr("|" & [q].[ParentID] & GetParent([q].[parentid]) & "|","|" & [w].[depid] & "|"))>0)) 
ORDER BY q.DepID, w.DepID DESC

но он (запрос) притормаживает
Нужно что-то более быстрое

  Ответить  
 
 автор: Vik   (20.08.2008 в 15:09)   личное сообщение
 
 

Навскидку - очень не советую использовать DLookup.

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

Попробуйте функцию построить на рекордсете без рекурсии.

Внутри фугкции цыклично ищете по рекордсету, пока находите, при этом собирая необходимую строку

  Ответить  
 
 автор: Pasat   (20.08.2008 в 16:42)   личное сообщение
 
 


спасибо что не бросаете

Я примерно так и мыслю
Как собрать строку вроде бы понятно.
Ну например соберется такая строка
anyStr = "/2;1/3;1/4;1;2/5;1;3/6;1;3/"

где
"2;1" это узел с ид = 2 и его предком с ид = 1
"4;1;2" это узел с ид = 4 и его предками с ид = 1 и ид = 2
каждый узел и его предки отделены "/"

Вот только что с ней делать дальше...
Не догоняю как из нее получить запрос

или такая строка
anyStr = "6;1;3"

где
"6;1;3" это узел с ид = 6 и его предки с ид = 1 и ид = 3

как эту строку вывести в запросе чтобы было так
6 1
6 3

  Ответить  
 
 автор: KrukVN   (20.08.2008 в 17:23)   личное сообщение
 
 

"SELECT ... FROM... WHERE(f1 in(" & anyStr & ")) or (f2 in(" & anyStr & "))"
не пойдет?
зы. только в качестве разделителя не точка с запятой, а запятая нужна (вроде)

  Ответить  
 
 автор: Vik   (20.08.2008 в 18:36)   личное сообщение
 
 

Поставте приблизительно такую функцию в запрос


Function strAllParenstID(ThisID As Long) As String
...
strAllParenstID = ""
Set rst = dbs.OpenRecordset("Select DepID, ParentID, Name1, from . . . . ")
StartFind:
rst.FindFirst "DepID = " & ThisID
If rst.NoMatch = False Then
    ThisID = rst!ParentID
    strAllParenstID = strAllParenstID & "." & ThisID
    GoTo StartFind
End If
rst.Close
...
End Function


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

Либо я чого-то недопонял...

  Ответить  
 
 автор: Pasat   (21.08.2008 в 08:13)   личное сообщение
24 Кб.
 
 

Спасибо VIK
Рассказываю
Создал ф-цию

Function strAllParenstID(ThisID As Long) As String
Dim dbs As Database
Dim rst As Recordset

strAllParenstID = ""
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("Departments", dbOpenDynaset)
StartFind:
rst.FindFirst "DepID = " & ThisID
If rst.NoMatch = False Then
    ThisID = rst!ParentID
    strAllParenstID = strAllParenstID & "." & ThisID
    GoTo StartFind
End If
rst.Close
End Function

Создал запрос
SELECT q.DepID, w.DepID
FROM Departments AS q, Departments AS w
WHERE (((InStr("." & [q].[ParentID] & strAllParenstID([q].[parentid]) & ".","." & [w].[depid] & "."))>0))
ORDER BY q.DepID, w.DepID DESC;

В результате выплняется медленнее чем при использывании Dlookup
А именно нужный запрос (673 записи) на осн.таблица из 100 записей отрывается 42 сек., а при использывании Dlookup – 33 сек. (см.аттач.)

Вообще то обе ф-ии не тормозят, т.е быстро формируют строку состоящую из «ид» предков
Тормозит выше указанный запрс

Поэтому вопрос в следующем
Как построить более быстрый запрос

Зы KrukVN – пока не успел разобраться с тем что Вы написали

  Ответить  
 
 автор: KrukVN   (21.08.2008 в 09:31)   личное сообщение
 
 

напишите хотяб так:

Function strAllParenstID(ThisID As Long) As String
Dim rst As DAO.Recordset

    Set rst = Workspaces(0).Databases(0).OpenRecordset("Departments", dbOpenSnapshot)
    
StartFind:
    rst.FindFirst "DepID = " & ThisID
    
    If rst.NoMatch = False Then
        ThisID = rst!ParentID
        strAllParenstID = strAllParenstID & "." & ThisID
        GoTo StartFind
    End If

rst.Close
Set rst = Nothing
End Function

и скорость Вас приятно удивит
***
но все равно медленно как-то... на 100 записях такая непозволительная тормозня...

  Ответить  
 
 автор: Pasat   (21.08.2008 в 16:53)   личное сообщение
 
 

Спасибо
Вроде работает по веселее
"но все равно медленно как-то... " это точно

  Ответить  
 
 автор: Vik   (21.08.2008 в 21:06)   личное сообщение
 
 

Думаю, основная проблема по скорости - обработка строк в условиях запроса и
двойное открывание одной и той-же таблицы.

Еще один вариант:



Function HaveThisParenstID(ThisID As Long, ThisParent as Long) As Boolean
Dim rst As DAO.Recordset
HaveThisParenstID = False
    Set rst = Workspaces(0).Databases(0).OpenRecordset("Departments", dbOpenSnapshot)
    StartFind:
    rst.FindFirst "DepID = " & ThisID
    If rst.NoMatch = False Then
        ThisID = rst!ParentID
             If ThisID  = ThisParent  Then
                     HaveThisParenstID = True
                     GoTo EndFunction
             EndIf
        GoTo StartFind
    End If
EndFunction:
rst.Close
Set rst = Nothing
End Function 



Еще - сделайте Parent-поле индексированным.

Возможны ошибки, писал в броузере, но суть должна быть понятна.

После запросом выбираете все записи, для коих результат этой функции = True

Там еще раньше было предложение заполнять через функцию временную таблицу.

  Ответить  
 
 автор: Pasat   (21.08.2008 в 22:27)   личное сообщение
 
 

еще раз СПАСИБО что не сдаетесь
Поставил ф-ию в запрос так
SELECT Departments.DepID, Departments.ParentID, HaveThisParenstID([DepID],[ParentID]) AS FunctTest FROM Departments

результат этой функции для всех записей = True
"После запросом выбираете все записи, для коих результат этой функции = True"
соответственно и выбирать нечего...
или
надо было не так ???
Если честно, то не совсем понял где изюм
Для какой записи должно быть True, а для какой False ???

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

С уважением ПАСАТ

  Ответить  
 
 автор: Vik   (22.08.2008 в 09:11)   личное сообщение
 
 

Pasat, уточните задачу.

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

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

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

4. Еще что-то.

Подный роддом...

  Ответить  
 
 автор: Pasat   (22.08.2008 в 10:19)   личное сообщение
 
 

Доброе утро
Задача такая
Нужно получить отдельными записями всех "родителей" для всех "детей"
В принципе задачу мы уже решили:
т.е. ф-ей (GetParent - автор ГлазастыйМышь или strAllParenstID - автор Vik) получили строку в которой через разделитель выводятся все предки для каждого узла.
Потом запросом
SELECT q.DepID, w.DepID  
FROM Departments AS q, Departments AS w  
WHERE (((InStr("|" & [q].[ParentID] & GetParent([q].[parentid]) & "|","|" & [w].[depid] & "|"))>0))  
ORDER BY q.DepID, w.DepID DESC

Получаем нужный набор записей (очень медленно )
Нужно быстрее (нужен более быстрый запрос)

ЗЫ аттач уже есть в этой ветке
автор: Pasat (21.08.2008 в 08:13)

  Ответить  
 
 автор: Vik   (22.08.2008 в 12:30)   личное сообщение
 
 

Уточните, что Вы имеете ввиду под "детьми":

1. Записи, которые не имеют детей

2. Все записи, имеющие родителей.

Генеалогия, однако

  Ответить  
 
 автор: Pasat   (22.08.2008 в 12:35)   личное сообщение
 
 

Посмотрите самое первое сообщение по этому вопросу

  Ответить  
 
 автор: Vik   (22.08.2008 в 12:39)   личное сообщение
 
 

ОК, сейчас будет еще один вариант.

  Ответить  
 
 автор: Vik   (22.08.2008 в 13:53)   личное сообщение
28 Кб.
 
 

Реализовано через временную таблицу
Перед запуском не забывайте ее очищать.
Запрос также возвращает кол-во предков.



Function InsetrParentsInTMP(ThisID As Long) As Long

Dim rst As DAO.Recordset
Dim strSQL_Insert As String
Dim CurID As Long

InsetrParentsInTMP = 0

CurID = ThisID
    
Set rst = CurrentDb.OpenRecordset("qw_ForTMP")

StartFind:
    rst.FindFirst "DepID = " & CurID
    If rst.NoMatch = False Then
        CurID = rst!ParentID
        strSQL_Insert = "INSERT INTO tblTMP ( DepIDTMP, ParentIDTMP ) VALUES ( " & ThisID & ", " & CurID & ");"
        DoCmd.SetWarnings False
        CurrentDb.Execute strSQL_Insert
        DoCmd.SetWarnings True
        InsetrParentsInTMP = InsetrParentsInTMP + 1
        GoTo StartFind
    End If
rst.Close
Set rst = Nothing
End Function



Смотрите присоединенній файл.
Возможно, нету необходимости в SetWarnings/
Записи с "нулевым" предком исключаються так

    If rst.NoMatch = False AND rst!ParentID<>0 Then

На всякий случай проверьте корректность работы

  Ответить  
 
 автор: Pasat   (22.08.2008 в 15:18)   личное сообщение
 
 

1. Мысль вроде понял
Бежим по дереву и найденные значения укладываем во временную таблицу

2.Значит Вы все-таки считаете, что с запросом мучиться не стоит, а лучше использывать временную таблицу ???
3.
На всякий случай проверьте корректность работы

Немного потестировал и обнаружил, что некоторые записи дублируются
Попробую разобраться до понедельника
Результат обязательно напишу

Хороших выходных
...жаль что пиво не настоящее

  Ответить  
 
 автор: Vik   (22.08.2008 в 16:15)   личное сообщение
 
 

Это уже нормально работает, только без запроса


Function InsetrParentsInTMP_2() As Long

Dim rst1 As DAO.Recordset
Dim rst2 As DAO.Recordset

Dim strSQL As String
Dim CurID As Long

InsetrParentsInTMP_2 = 0

strSQL = "DELETE tblTMP.* FROM tblTMP;"
CurrentDb.Execute strSQL

Set rst1 = CurrentDb.OpenRecordset("qw_ForTMP")
Set rst2 = CurrentDb.OpenRecordset("qw_ForTMP")

rst1.MoveLast
rst1.MoveFirst


Do While Not rst1.EOF

CurID = rst1!DepID

StartFind:
    rst2.FindFirst "DepID = " & CurID
    If rst2.NoMatch = False Then
        CurID = rst2!ParentID
        strSQL = "INSERT INTO tblTMP ( DepIDTMP, ParentIDTMP ) VALUES ( " & rst1!DepID & ", " & CurID & ");"
        CurrentDb.Execute strSQL
        InsetrParentsInTMP_2 = InsetrParentsInTMP_2 + 1
        GoTo StartFind
    End If
    
rst1.MoveNext
Loop

rst1.Close
Set rst1 = Nothing
rst2.Close
Set rst2 = Nothing
End Function


Ухожу в отпуск, поэтому в ближайшие 2 недели вряд-ли буду часто на форуме.

  Ответить  
 
 автор: Pasat   (22.08.2008 в 17:19)   личное сообщение
 
 

Ура
Спешу сообщить - работает отменно (3-4 сек.)
Наверное большую скорость получить невозможно ???

ОГРОМНОЕ СПАСИБО
и
отличного отпуска

  Ответить  
 
 автор: Vik   (22.08.2008 в 19:03)   личное сообщение
 
 

Спасибо.
Удачи!

  Ответить  
 
 автор: Vik   (22.08.2008 в 19:04)   личное сообщение
 
 

PS Думаю, что резервы для улучшения существуют, но вряд-ли для Вас критична эта секунда либо ее доли...
Хотя как там в фильме "17 мгновений весны" - не думай о секундах свысока.

  Ответить  
HiProg.com - Технологии программирования
Rambler's Top100 TopList