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

Форум: MS ACCESS

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

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

 
 

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

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

тема: помогите с написанием процедурки!
 
 автор: alex-freeman   (06.08.2010 в 15:16)   личное сообщение
 
 

Хочу выполнить N раз запрос на добавление, в котором условием отбора будет значение поля таблицы, содержащей N записей. Т.е. циклично выполнить запрос для каждой записи таблицы.
Понимаю, что в процедуре должен использоваться рекордсет, переходящий при каждой итерации цикла к следующей записи, но как засунуть его в запрос и потом записать результаты в конечную таблицу? Просто я почти никогда не касался VBA и в программировании ламер.
Просто подскажите как организовать тело процедуры, какие методы и функции использовать. Дальше постараюсь сам разобраться.
Сам пока читаю "программирование на ВБА"
Спасибо всем, готовым помочь новичку!

  Ответить  
 
 автор: osmor   (06.08.2010 в 15:39)   личное сообщение
 
 

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

  Ответить  
 
 автор: alex-freeman   (06.08.2010 в 16:10)   личное сообщение
 
 

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

  Ответить  
 
 автор: kot_k_k   (06.08.2010 в 17:11)   личное сообщение
 
 

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

  Ответить  
 
 автор: alex-freeman   (07.08.2010 в 15:53)   личное сообщение
 
 

kot_k_k, к сожалению нет. (( Тут ни Sum, ни Dsum не поможет, но ни в этом дело. Запрос с расчетом нарастающего итога по группам я сделал, но он очень низкопроизводительный, и я хочу его оптимизировать.
Могу более детально описать ситуацию на примере.

Например исходный массив, который я предварительно собираю запросом:
№ Компания дата Сумма
1 К1 01.01.2010 100
2 К1 02.01.2010 0
3 К1 03.01.2010 -20
4 К2 01.01.2010 0
5 К2 02.01.2010 0
6 К2 03.01.2010 50
7 К3 01.01.2010 30
8 К3 02.01.2010 -20
9 К3 03.01.2010 5
N ...... ....... ....

Нужно было получить нар.итог и записать результат в таблицу (в след виде):
№ Компания дата Нар.итог
1 К1 01.01.2010 100
2 К1 02.01.2010 100
3 К1 03.01.2010 80
4 К2 01.01.2010 0
5 К2 02.01.2010 0
6 К2 03.01.2010 50
7 К3 01.01.2010 30
8 К3 02.01.2010 10
9 К3 03.01.2010 15
N .... ... ....
Если через Sum, тогда на 01.01.2010 сумма будет 130 для к1,к2 и к3, на 02.01.2010 - 110 и т.д.. Т.е. сложит все без группировки.
Я нар.итог посчитал как:
Нар.итог: (SELECT Sum(T.Сумма) FROM Таблица1 As T WHERE (Таблица1.Компания=T.[Компания]) And (T.[Дата]<=Таблица.[Дата]) )
Это рекурсия и для выполнения запроса производится N^2 итераций. Записей сейчас ок.10тыс., что дает 100млн. итераций, каждая из которых связана с кучей расчетов (не только по этому полю). Мой 4ядерный комп на этот запрос тратит более 2-х часов.

Поэтому я хочу оптимизировать процесс - и в процедуре считать нар.итог отдельно для к1, потом к2 и к3 (уже без рекурсии, через Sum). И последовательно записывать результат в итоговую таблицу.

Вот мой вопрос - как мне написать такую процедуру?
Думаю что ничего сложного, просто в ВБА ничего не секу ;)

Если будут другие идеи по реализации задачи буду рад!

  Ответить  
 
 автор: Lukas   (07.08.2010 в 16:44)   личное сообщение
 
 


Нар.итог: (SELECT Sum(T.Сумма) FROM Таблица1 As T WHERE (Таблица1.Компания=T.[Компания]) And (T.[Дата]<=Таблица.[Дата]) )
Это рекурсия и для выполнения запроса производится N^2 итераций.


Вот здесь вы ошибаетесь ИМХО.
Никакой рекурсии я тут не наблюдаю.
Для каждой записи Таблица1 будет выполнен ОДИН суммирующий запрос.

Выполнение этих суммирующих запросов при посредничестве VBA только затормозит расчет.

Наличие индексов по полям Таблица1.Компания и Таблица.[Дата] могут ускорить первоначальный запрос.

Надеюсь поле Таблица1.Компания имеет тип Long и содержит внешний ключ на справочную таблицу компаний?
Если нет, и это поле типа Text, то это и есть "главный тормоз".

  Ответить  
 
 автор: alex-freeman   (08.08.2010 в 09:28)   личное сообщение
 
 


Никакой рекурсии я тут не наблюдаю.
Для каждой записи Таблица1 будет выполнен ОДИН суммирующий запрос.


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



Надеюсь поле Таблица1.Компания имеет тип Long и содержит внешний ключ на справочную таблицу компаний?


к сожалению, тут вы правы "Таблица1.Компания" - это текстовое поле. Я его связал с ключевой таблицей и включил индексацию по Компания и Дата. В результате +1/3 производительности. Это конечно хорошо, за что, Lukas, большое спасибо! Но в целом проблему не решает. Если бы уменьшить время в разы...
Все же хочу сделать что запланировал, чувствую, что должно помочь. Ведь тогда, вместо того геморойного подзапроса для "нар.итог" всей исходной таблицы достаточно будет делать обычную группировку с суммированием для каждой группы: к1,к2 и т.д.

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

Кстати, может есть другой способ рассчитать поле "нар.итог" из моего примера?

  Ответить  
 
 автор: alex-freeman   (07.08.2010 в 16:14)   личное сообщение
57 Кб.
 
 

Параллельно еще вопрос.
Стал разбираться в азах модели ADO и в самом начале затыка.
Компилятору не нравится строчка: Dim rsTransh As ADODB.Recordset
Ругается на определение типа переменной (см. вложение)
Как что поправить? Вроде же этот стандартный тип в Access?

  Ответить  
 
 автор: Lukas   (07.08.2010 в 16:47)   личное сообщение
 
 

Ну так компилятор и говорит, что нет описания этого типа/класса.
То есть не подключена библиотека ADO.

  Ответить  
 
 автор: alex-freeman   (07.08.2010 в 16:53)   личное сообщение
 
 

Спасибо! Библиотеку подключил, дело пошло дальше ))

  Ответить  
 
 автор: Lvm   (09.08.2010 в 11:10)   личное сообщение
 
 

Можно сделать что-то типа этого:

Dim Db As Database
Dim Rs As Recordset
Dim Itog As Long
Set Db = CurrentDb
Set Rs = Db.OpenRecordset("SELECT DISTINCT Компания FROM Tabl", dbOpenDynaset)
Rs.MoveFirst
Do Until Rs.EOF
Set Rs1 = Db.OpenRecordset("SELECT * FROM Tabl WHERE Компания=""" & Rs.[Компания] & """ ORDER BY Дата", dbOpenDynaset)
Rs1.MoveFirst
Do Until Rs1.EOF
Itog = Itog + Rs1.[Сумма]
Rs1.[Итог] = Itog
... Ну, и другие расчеты ...
Rs1.Update
Rs1.MoveNext
Loop
Rs1.Close
Rs.MoveNext
Loop
Rs.Close
Db.Close

Это конечно не SQL, но зато никакой рекурсии - последовательное обращение к записям.
Даже 10 тыс. записей должны посчитаться довольно быстро.

ADO не юзаю, уж извиняйте...

  Ответить  
 
 автор: alex-freeman   (10.08.2010 в 11:45)   личное сообщение
 
 

Спасибо, большое! Буду пробовать.
Как сделаю, отпишусь.

  Ответить  
 
 автор: alex-freeman   (10.08.2010 в 15:13)   личное сообщение
24 Кб.
 
 


Set Rs1 = Db.OpenRecordset("SELECT * FROM Tabl WHERE Компания=""" & Rs.[Компания] & """


Lvm, ругается на отсутствие такого метода (см. вложение). Может как-то по другому надо обращаться к полю?
Я смысл ошибки понимаю, но т.к. не знаю VBA, опять прошу Вашей подсказки.

  Ответить  
 
 автор: Lvm   (11.08.2010 в 05:32)   личное сообщение
 
 

Убери везде " As Recordset"
Не спрашивайте, почему - не знаю...

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