Форум Рідного Міста
Ви не ввійшли [Ввійти - Зареєструватися]
Вниз

Версія для друку  
Автор: Тема: VBA for Access
Юрій Марків
Академік
****

Фотографія користувача


Повідомлень: 795
Зареєстрований: 10-12-2003
Місто: Lviv
Нема на форумі

Настрій: :-)

[*] написано 31-1-2009 у 16:57
VBA for Access


Привіт, люди!

Така задачка.
Імпортую один екселівський файл в Access за допомогою коду VBA
Цитата:
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel97, "TableName", "C:\File.xls"


Тим часом знадобилося імпортувати в окремі таблиці кілька сотень таких файлів, імена файлів вказані в таблиці Access table3, таблиці повинні називатися так, як файли.

Хтось підкаже, як це зробити?

Переглянути профіль користувача Зайти на домашню сторінку користувача Переглянути всі повідомлення цього користувача
Юрій Марків
Академік
****

Фотографія користувача


Повідомлень: 795
Зареєстрований: 10-12-2003
Місто: Lviv
Нема на форумі

Настрій: :-)

[*] написано 31-1-2009 у 21:56


Я тут по ходу п'єси вже дещо накалякав для імпорту купи файлів у таблиці Access:

Цитата:
Sub test()
Dim rstCurr As DAO.Recordset
Dim dbsCurr As Database
Dim MyPath As String
Dim MyFile As String
Dim ShortFile As String
MyPath = "C:\Marchello\"
Set dbsCurr = Access.CurrentDb
Set rstCurr = dbsCurr.OpenRecordset("Table1", dbOpenDynaset)
MyFile = Dir(MyPath)
Do While MyFile <> ""
rstCurr.AddNew
rstCurr.Fields("1").Value = Time$
rstCurr.Fields("2").Value = Date$
rstCurr.Fields("3").Value = MyPath
rstCurr.Fields("4").Value = MyFile
rstCurr.Update
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel97,
MyFile, MyPath & MyFile
MyFile = Dir
Loop


Тепер ще залишилася теж нетривіальна частина роботи.

Потрібно пройти кожну стрічку таблиць Access iз іменами r* .
Структура даних таблиць (працюємо лише з стовпчиком "F2") :

створення

зміна

вилучення


Принаймні один з блоків мусить бути непорожнім (або й кожен), наприклад:

таблиця "r071203_xls"

створення
9129001

зміна
6026008

вилучення


Таким чином, потреба полягає в тому, щоб построково проаналізувати кожну таблицю "r*", знайти семизначні цифрові коди в кожному блоці і створити нову таблицю:

поле1: назва таблиці "r*"
поле2: 7-значний числовий код
поле3: створення, зміна чи вилучення

Я на програміста ніколи не вчився...
Можливо, хтось щось підкаже?

Переглянути профіль користувача Зайти на домашню сторінку користувача Переглянути всі повідомлення цього користувача
Юрій Марків
Академік
****

Фотографія користувача


Повідомлень: 795
Зареєстрований: 10-12-2003
Місто: Lviv
Нема на форумі

Настрій: :-)

[*] написано 1-2-2009 у 11:29


Поки ніхто не відповідає, пишу сюди, що наразі в мене вийшло...

Ось приклад таблиці Access, з якою я працюю (прінтскрін) :
http://marchello.ccx-grads.org/example.jpg

На виході потрібно отримати таблицю з полями:
1) назва таблиці
2) 7-значний код
3) дія (create, change або delete)

Ось мій код для аналізу таблиць:

Цитата:
Sub test()

Dim db As DAO.Database, tdf As DAO.TableDef
Dim strAction As String
Dim rstIn As DAO.Recordset, rstOut As DAO.Recordset

' Point to this database
Set db = CurrentDb
' Open the output recordset
Set rstOut = db.OpenRecordset("tblOutput", _
dbOpenDynaset, dbAppendOnly)
' Loop through all tabledefs
For Each tdf In db.TableDefs
' Look for a table name starting with "r"
'If tdf.Name Like "r*" Then
If Left(tdf.Name, 1) = "r" Then
' Found one - open it
Set rstIn = db.OpenRecordset("SELECT F2 " & _
"FROM [" & tdf.Name & "] " & _
"WHERE Len(F2 & """") = 0")
' Process all the records
Do Until rstIn.EOF
' See if keyword
If (rstIn!F2 = "Create") Or (rstIn!F2 = "Change") _
Or (rstIn!F2 = "Delete") Then
' Just save the action
strAction = rstIn!F2
Else
' Make sure we have a good action
If Len(strAction) > 0 Then
' Write an output record
rstOut.AddNew
rstOut!Field1 = tdf.Name
rstOut!Field2 = rstIn!F2
rstOut!Field3 = strAction
rstOut.Update
End If
End If
' Get the next record
rstIn.MoveNext
Loop
' Close the input
rstIn.Close
End If
' Get the next table
Next tdf
' Clean up
rstOut.Close
Set rstIn = Nothing
Set rstOut = Nothing
Set tdf = Nothing
Set db = Nothing

End Sub


Наразі не спрацьовує. Хтось може підказати, чому?

Переглянути профіль користувача Зайти на домашню сторінку користувача Переглянути всі повідомлення цього користувача
Aндpiй
Дійсний член
***



Повідомлень: 128
Зареєстрований: 30-4-2003
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 1-2-2009 у 13:28


Не спрацьовує тому, що В SQL-запиті

Set rstIn = db.OpenRecordset("SELECT F2 " & _
"FROM [" & tdf.Name & "] " & _
"WHERE Len(F2 & """") = 0")

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

Set rstIn = db.OpenRecordset("SELECT F2 " & _
"FROM [" & tdf.Name & "] " & _
"WHERE Len(F2 & """") > 0")


P.S. Можете надалі звертатись до мене стосовно VBA
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Юрій Марків
Академік
****

Фотографія користувача


Повідомлень: 795
Зареєстрований: 10-12-2003
Місто: Lviv
Нема на форумі

Настрій: :-)

[*] написано 1-2-2009 у 14:14


Цитата:
Оригінальне повідомлення від Aндpiй
стоїть умова відбирати лише порожні значення із вхідної таблиці, а нам треба - лише непорожні, тобто

Set rstIn = db.OpenRecordset("SELECT F2 " & _
"FROM [" & tdf.Name & "] " & _
"WHERE Len(F2 & """") > 0")


Дякую, Андрію! :)))))
Нарешті від вчорашнього ранку помиюся, переодягнуся, поїм і взагалі вийду на вулицю! :D

Переглянути профіль користувача Зайти на домашню сторінку користувача Переглянути всі повідомлення цього користувача
Павло Жежнич
Модератор
******

Фотографія користувача


Повідомлень: 1139
Зареєстрований: 24-11-2002
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 1-2-2009 у 14:16


Питання/пропозиції:
1) Чи структура файлів однакова? Якщо так, то чи не краще створити таблицю-лінк file_xls на File.xls, а при імпорті потрібного файлу робити його копію на "C:\File.xls". Тоді весь імпорт буде виглядати так:

SQLtext = " INSERT INTO TableName (<поля>;) SELECT <поля> FROM file_xls; "
CurrentDB.Execute SQLtext

2) Вибір порожніх/непорожніх краще здійснювати умовою
" WHERE F2 IS NULL " / " WHERE F2 IS NOT NULL "

3) Взагалі я б рекомендував для вставки/видалення/редагування (всюди де можна) використовувати SQL-запити, а не рекордсети.





Львів, який ми бачимо щодня - Фотожурнал Львова. Особистий блог - PZhe.Net.
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Aндpiй
Дійсний член
***



Повідомлень: 128
Зареєстрований: 30-4-2003
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 1-2-2009 у 14:40


Павло Жежнич,
пожалійте людину - він же сказав, що на програміста ніколи не вчився :)

Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Юрій Марків
Академік
****

Фотографія користувача


Повідомлень: 795
Зареєстрований: 10-12-2003
Місто: Lviv
Нема на форумі

Настрій: :-)

[*] написано 1-2-2009 у 14:43


Цитата:
Оригінальне повідомлення від Aндpiй
Павло Жежнич,
пожалійте людину - він же сказав, що на програміста ніколи не вчився :)



+1 ;)

Та все одно дуже дякую за участь, Павло!
Переглянути профіль користувача Зайти на домашню сторінку користувача Переглянути всі повідомлення цього користувача
Павло Жежнич
Модератор
******

Фотографія користувача


Повідомлень: 1139
Зареєстрований: 24-11-2002
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 2-2-2009 у 13:41


Цитата:
Оригінальне повідомлення від Aндpiй
Павло Жежнич,
пожалійте людину - він же сказав, що на програміста ніколи не вчився :)

Якщо людина на програміста не вчилася, то вона повинна бути зацікавлена писати як найменше програмного коду! :) Я власне це рекомендую.
А написання SQL-запитів - це не програмування - один "правильний" запит може замінити десятки стрічок програмного коду.





Львів, який ми бачимо щодня - Фотожурнал Львова. Особистий блог - PZhe.Net.
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Aндpiй
Дійсний член
***



Повідомлень: 128
Зареєстрований: 30-4-2003
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 2-2-2009 у 14:52


Цитата:

Якщо людина на програміста не вчилася, то вона повинна бути зацікавлена писати як найменше програмного коду! Я власне це рекомендую.

Я думаю, що п.Юрію, хоча він робить перші кроки, вдалось написати власноруч менше коду, ніж найбільшому асу в програмуванні :sing:

Пане Павле - цікаво було б побачити ваш варіант рішення цієї задачі за допомогою SQL без використання VBA
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Юрій Марків
Академік
****

Фотографія користувача


Повідомлень: 795
Зареєстрований: 10-12-2003
Місто: Lviv
Нема на форумі

Настрій: :-)

[*] написано 2-2-2009 у 23:51


Ще цікавить, як витягнути кожну назву листа екселівського файлу і додати в таблицю tblOutput

Цитата:
rstOut!Field4 = ...
Переглянути профіль користувача Зайти на домашню сторінку користувача Переглянути всі повідомлення цього користувача
Aндpiй
Дійсний член
***



Повідомлень: 128
Зареєстрований: 30-4-2003
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 3-2-2009 у 11:02


П.Юрію, доведеться використовувати інший підхід, який до-речі, дозволяє відмовитися від TransferSpreadsheet, бо вже можна безпосередньо керувати всіма об'єктами Excel

Раніше наведена програма матиме вигляд (додані стрічки - з коментарями)

Цитата:

Sub test()
Dim rstCurr As DAO.Recordset
Dim dbsCurr As Database
Dim MyPath As String
Dim MyFile As String
Dim ShortFile As String

Dim myOlApp As Object 'об'єкт Excel
Dim MyWo As Excel.Workbook 'книга
Dim mysheet As Excel.Worksheet 'сторінка
Set myOlApp = CreateObject("excel.Application") 'встановлюємо зв'язок з Excel


MyPath = "C:\Marchello\"
Set dbsCurr = Access.CurrentDb
Set rstCurr = dbsCurr.OpenRecordset("Table1", dbOpenDynaset)
MyFile = Dir(MyPath)
Do While MyFile <> ""

Set MyWo = myOlApp.Workbooks.Open(MyPath & MyFile) 'відкриваємо документ
For Each mysheet In MyWo.Worksheets 'переглядаємо всі сторінки
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel97, "a", MyPath & MyFile, , mysheet.Name & "$" ' тут вказуємо додатковий параметр - яку сторінку



rstCurr.AddNew
rstCurr.Fields("1").Value = Time$
rstCurr.Fields("2").Value = Date$
rstCurr.Fields("3").Value = MyPath
rstCurr.Fields("4").Value = MyFile
rstCurr.Fields("5").Value = mysheet.Name 'це назва сторінки (додати поле в таблицю)
rstCurr.Update

Next mysheet 'беремо наступну сторінку
MyWo.Close 'звільняємо

MyFile = Dir
Loop

End Sub



В програмі додати в меню Сервис-ссылки: Microsoft Excel nn Object Library
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Павло Жежнич
Модератор
******

Фотографія користувача


Повідомлень: 1139
Зареєстрований: 24-11-2002
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 3-2-2009 у 12:31


Цитата:
Оригінальне повідомлення від Aндpiй
Пане Павле - цікаво було б побачити ваш варіант рішення цієї задачі за допомогою SQL без використання VBA

Питання не стоїть, що треба відмовлятися від VBA. Просто у частині коду, де можна, я стараюся використовувати SQL-код, а не VBA-код. Стилістично це виглядає приблизно так:

Цитата:

Sub test()
Dim SQLtext As String
Dim dbsCurr As Database
Dim MyPath As String
Dim MyFile As String
Dim ShortFile As String

Dim myOlApp As Object 'об'єкт Excel
Dim MyWo As Excel.Workbook 'книга
Dim mysheet As Excel.Worksheet 'сторінка
Set myOlApp = CreateObject("excel.Application") 'встановлюємо зв'язок з Excel


MyPath = "C:\Marchello\"
Set dbsCurr = Access.CurrentDb
Set rstCurr = dbsCurr.OpenRecordset("Table1", dbOpenDynaset)
MyFile = Dir(MyPath)
Do While MyFile <> ""

Set MyWo = myOlApp.Workbooks.Open(MyPath & MyFile) 'відкриваємо документ
For Each mysheet In MyWo.Worksheets 'переглядаємо всі сторінки
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel97, "a", MyPath & MyFile, , mysheet.Name & "$" ' тут вказуємо додатковий параметр - яку сторінку

'-----------
SQLtext = " INSERT INTO Table1 (F1, F2, F3, F4, F5) " _
& " VALUES ('" & Time$ & "', '" & Date$ & "', '" & MyPath & "', '" & MyFile & "', '" & mysheet.Name & "');"
CurrentDB.Execute SQLtext
'-----------

Next mysheet 'беремо наступну сторінку
MyWo.Close 'звільняємо

MyFile = Dir
Loop

End Sub


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





Львів, який ми бачимо щодня - Фотожурнал Львова. Особистий блог - PZhe.Net.
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Aндpiй
Дійсний член
***



Повідомлень: 128
Зареєстрований: 30-4-2003
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 3-2-2009 у 12:43


Використовуючи автоматизацію без імпорту xls-файлу в тимчасову таблицю можна обійтись в будь-якому випадку
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Павло Жежнич
Модератор
******

Фотографія користувача


Повідомлень: 1139
Зареєстрований: 24-11-2002
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 3-2-2009 у 12:53


Спочатку треба зробити копію одного з файлів у import.xls, далі - створити лінк на перший листок цього файлу через меню "Файл/Зовнішні дані/Зв'язок з таблицями". Створений лінк назвати "import_xls". Тоді код може виглядати приблизно так:

Цитата:

Sub test()
Dim SQLtext As String, rs AS DAO.Recordset
Dim MyPath As String

MyPath = "C:\Marchello\"
Dim MyFile As String
MyFile = Dir(MyPath)

While MyFile <> ""
Kill MyPath & "import.xls"
FileCopy MyPath & MyFile, MyPath & "import.xls"
SQLtext = " SELECT F1, F2, F3, F4, F5 FROM import_xls "
Set rs = CurrentDB.OpenRecorset(SQLtext)
While Not rs.EOF
'-----------
'Тут треба аналізувати вміст rs!F1,...,rs!F5
'і вставляти у потрібну таблицю
'(приклад вставки у попередньому дописі)
'-----------
rs.MoveNext
Wend

MyFile = Dir
Wend

End Sub






Львів, який ми бачимо щодня - Фотожурнал Львова. Особистий блог - PZhe.Net.
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Павло Жежнич
Модератор
******

Фотографія користувача


Повідомлень: 1139
Зареєстрований: 24-11-2002
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 3-2-2009 у 13:00


Цитата:
Оригінальне повідомлення від Aндpiй
Використовуючи автоматизацію без імпорту xls-файлу в тимчасову таблицю можна обійтись в будь-якому випадку

Звичайно, але тоді треба аналізувати вміст xls-файлу через об'єкти Workbook і Worksheet. А це робить програмний код залежним від формату імпортованих файлів.

Наприклад, припустимо що ситуація поміняється і файли будуть надходити не в xls-форматі, а в текстовому. Тоді треба буде досить сильно міняти програмний код.





Львів, який ми бачимо щодня - Фотожурнал Львова. Особистий блог - PZhe.Net.
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Aндpiй
Дійсний член
***



Повідомлень: 128
Зареєстрований: 30-4-2003
Місто: Львів
Нема на форумі

Настрій: Настрій не вказаний

[*] написано 3-2-2009 у 13:46


Найефективніший спосіб написання програмного коду - це метод "Copy-Paste":lol:
Переглянути профіль користувача Переглянути всі повідомлення цього користувача
Юрій Марків
Академік
****

Фотографія користувача


Повідомлень: 795
Зареєстрований: 10-12-2003
Місто: Lviv
Нема на форумі

Настрій: :-)

[*] написано 14-2-2009 у 09:58


Добрався до цього питання, вже підходить час, коли потрібно завершити...

В мене Access 2003, Microsoft Excel 11.0 Object Library.

При виконанні стрічки "rstCurr.Fields("1").Value = Time$" отримую помилку: "Run-time error '3265': Элемент не обнаружен в данном семействе."

В чому може бути справа?

Цитата:
Оригінальне повідомлення від Aндpiй

Цитата:

Sub test()
Dim rstCurr As DAO.Recordset
Dim dbsCurr As Database
Dim MyPath As String
Dim MyFile As String
Dim ShortFile As String

Dim myOlApp As Object 'об'єкт Excel
Dim MyWo As Excel.Workbook 'книга
Dim mysheet As Excel.Worksheet 'сторінка
Set myOlApp = CreateObject("excel.Application") 'встановлюємо зв'язок з Excel


MyPath = "C:\Marchello\"
Set dbsCurr = Access.CurrentDb
Set rstCurr = dbsCurr.OpenRecordset("Table1", dbOpenDynaset)
MyFile = Dir(MyPath)
Do While MyFile <> ""

Set MyWo = myOlApp.Workbooks.Open(MyPath & MyFile) 'відкриваємо документ
For Each mysheet In MyWo.Worksheets 'переглядаємо всі сторінки
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel97, "a", MyPath & MyFile, , mysheet.Name & "$" ' тут вказуємо додатковий параметр - яку сторінку



rstCurr.AddNew
rstCurr.Fields("1").Value = Time$
rstCurr.Fields("2").Value = Date$
rstCurr.Fields("3").Value = MyPath
rstCurr.Fields("4").Value = MyFile
rstCurr.Fields("5").Value = mysheet.Name 'це назва сторінки (додати поле в таблицю)
rstCurr.Update

Next mysheet 'беремо наступну сторінку
MyWo.Close 'звільняємо

MyFile = Dir
Loop

End Sub



В програмі додати в меню Сервис-ссылки: Microsoft Excel nn Object Library
Переглянути профіль користувача Зайти на домашню сторінку користувача Переглянути всі повідомлення цього користувача

  Догори

Статичне дзеркало форуму

Львів
Pоwered by XМB
Developed by Avеnture Media & The XМB Group © 2002-2006



Інші проекти:
Наука-Онлайн - Об'єднання українських науковців
Львів - Фотоблог міста
ІБАС. Інформаційна, бібліотечна та архівна справа - Сучасна освітня спеціальність
School review 7224
Реклама: