jak automatycznie otworzyć kolejny plik accessa, po zakończeniu aklualizacji obecnie otwartego.

0

Pytanie jak w tytule, a sprawa wygląda następująco. Muszę codziennie aktualizować pliki/bazy access-owe, które ze względu na wielkość są podzielone na kilka plików. Każdy plik musi się aktualizować w odpowiedniej kolejności. Do tej pory mam to ustawione w harmonogramie w godzinach nocnych, kiedy sieć nie jest mocno obciążona i każdy plik ma szytwno ustawioną godzinę. Każdy plik posiada autoexec, który uruchamia makro, utworzone poprzez wybranie akcji z listy, a nie VBA. Dzięki temu forum wiem już, że można takie makro konwertować na VBA, które dla przykładowego pliku wygląda jak poniżej.

Function aktualizacja()
On Error GoTo aktualizacja_Err

    DoCmd.SetWarnings False
    DoCmd.OpenQuery "00_czysci tabela_moje_kody", acViewNormal, acEdit
    DoCmd.OpenQuery "00_aktualizuje tabela_moje_kody", acViewNormal, acEdit
    DoCmd.OpenQuery "00_czysci tabela_sprzed_dzienna_30", acViewNormal, acEdit
    DoCmd.OpenQuery "00_aktualizuje tabela_sprzed_dzienna_30", acViewNormal, acEdit
    DoCmd.OpenQuery "00_tworzy tabela_regulacji_mag_surowe", acViewNormal, acEdit
    DoCmd.OpenQuery "00_czysci tabela_MEA_teraz", acViewNormal, acEdit
    DoCmd.OpenQuery "00_nowe_aktualizuje tabela_MEA_teraz", acViewNormal, acEdit
    DoCmd.OpenQuery "00_czysci tabela_MEA", acViewNormal, acEdit
    DoCmd.OpenQuery "00_nowe_dodaje tabela_MEA_his", acViewNormal, acEdit
    DoCmd.OpenQuery "00_nowe_dodaje tabela_MEA_teraz", acViewNormal, acEdit
    DoCmd.OpenQuery "00_nowe_czysci tabela_sprzed_surowe_teraz", acViewNormal, acEdit
    DoCmd.OpenQuery "00_nowe_aktualizuje tabela_sprzed_surowe_teraz", acViewNormal, acEdit
    DoCmd.OpenQuery "00_nowe_czysci tabela_sprzed_surowe", acViewNormal, acEdit
    DoCmd.OpenQuery "00_nowe_dodaje sprzed_surowe_his", acViewNormal, acEdit
    DoCmd.OpenQuery "00_nowe_dodaje sprzed_surowe_teraz", acViewNormal, acEdit
    DoCmd.SetWarnings True
    DoCmd.Quit acSave


aktualizacja_Exit:
    Exit Function

aktualizacja_Err:
    MsgBox Error$
    Resume aktualizacja_Exit

End Function

Jest sposób na zmodyfikowanie takiego kodu, żeby po zakończeniu aktualizacji otwierał kolejny plik, który powinien być aktualizowany w następnej kolejności?

1

Użyj zewnętrznego pliku (Acess) powiedzmy nazwijmy go "Scheduler". Tak po krótce w Scheduler robisz funkcję która będzie najpierw sprawdzała status zadania i w zależności od niego będzie odpała kolejną bazę. Czyli będzie działać to na zasadzie:

  1. Odpal plik1
  2. Plik1 - robi co tam ma robić z autoexec + na koniec jak wszystko poszło wstawia status "Plik1- done" do Schedulera z datą.
  3. Odpal plik2
  4. Plik2 - autoexec + najpierw sprawdza czy poprzedni plik skończył poprawnie (po statusie) [no chyba, że tego nie potrzebujesz] i odpala resztę zadań
  5. Odpal plik3
    ...

Przykładowy kod w Schedulerze:

Public Function Run()

Dim accessApp

Set accessApp = Nothing
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase ("D:\Plik1.accdb") 'Odpala Plik1
Set accessApp = Nothing
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase ("D:\Plik2.accdb") 'odpala Plik 2
Set accessApp = Nothing
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase ("D:\Plik3.accdb") 'Odpala plik 3
Set accessApp = Nothing

DoCmd.RunCommand acCmdExit
End Function
0
BlackBad napisał(a):

Użyj zewnętrznego pliku (Acess) powiedzmy nazwijmy go "Scheduler". Tak po krótce w Scheduler robisz funkcję która będzie najpierw sprawdzała status zadania i w zależności od niego będzie odpała kolejną bazę. Czyli będzie działać to na zasadzie:

  1. Odpal plik1
  2. Plik1 - robi co tam ma robić z autoexec + na koniec jak wszystko poszło wstawia status "Plik1- done" do Schedulera z datą.
  3. Odpal plik2
  4. Plik2 - autoexec + najpierw sprawdza czy poprzedni plik skończył poprawnie (po statusie) [no chyba, że tego nie potrzebujesz] i odpala resztę zadań
  5. Odpal plik3
    ...

Przykładowy kod w Schedulerze:

Public Function Run()

Dim accessApp

Set accessApp = Nothing
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase ("D:\Plik1.accdb") 'Odpala Plik1
Set accessApp = Nothing
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase ("D:\Plik2.accdb") 'odpala Plik 2
Set accessApp = Nothing
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase ("D:\Plik3.accdb") 'Odpala plik 3
Set accessApp = Nothing

DoCmd.RunCommand acCmdExit
End Function

instrukcja zapisująca raport "done" do pliku powinna być umieszczona w pliku, który kończy działanie i dodatkowo przez DoCmd.SetWarnings True i DoCmd.Quit acSave jak na grafice poniżej

instrukcja.png

0

np coś takiego (przy założeniu że w bazie Plik1 wcześniej dodałeś Linked table do Schedulera i dodałeś tablice TblLog):

sql = "INSERT INTO TblLog ( LogDate, LogTime, Application ) SELECT Date() AS Expr1, Time() AS Expr3, 'File1 - Done' AS Expr2 FROM TblLog"
DoCmd.RunSQL sql

1

@BlackBad: ma dobry pomysł, tylko ja bym to zrobił inaczej, nie potrzebujesz otwierać bazy danych by robic/wywoływac na nich zapytania, powiem więcej nie musisz do tego używać access'a, wystarczy użyć nieśmiertelego vbcsripta do tego i napisać skrypt:

connStr = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source="
Set objConn = CreateObject("ADODB.Connection")

'AKTUALIZACJA DANYCH W PLIKU #1

plik = "c:\roboczy\baza1.accdb"
'Open Connection
objConn.open connStr & plik

with objConn
	.Execute "00_czysci tabela_moje_kody"
    .Execute "00_aktualizuje tabela_moje_kody"
    .Execute "00_czysci tabela_sprzed_dzienna_30"
    .Execute "00_aktualizuje tabela_sprzed_dzienna_30"
    .Execute "00_tworzy tabela_regulacji_mag_surowe"
    .Execute "00_czysci tabela_MEA_teraz"
    .Execute "00_nowe_aktualizuje tabela_MEA_teraz"
    .Execute "00_czysci tabela_MEA"
    .Execute "00_nowe_dodaje tabela_MEA_his"
    .Execute "00_nowe_dodaje tabela_MEA_teraz"
    .Execute "00_nowe_czysci tabela_sprzed_surowe_teraz"
    .Execute "00_nowe_aktualizuje tabela_sprzed_surowe_teraz"
    .Execute "00_nowe_czysci tabela_sprzed_surowe"
    .Execute "00_nowe_dodaje sprzed_surowe_his"
    .Execute "00_nowe_dodaje sprzed_surowe_teraz"
end with

objConn.Close


'AKTUALIZACJA DANYCH W PLIKU #2

plik = "c:\roboczy\baza2.accdb"
'Open Connection
objConn.open connStr & plik

with objConn
	.Execute "zapytanie do bazy 2"

end with

objConn.Close

'AKTUALIZACJA DANYCH W PLIKU #3

plik = "c:\roboczy\baza3.accdb"
'Open Connection
objConn.open connStr & plik

with objConn
	.Execute "zapytanie do bazy 3"

end with

objConn.Close

Oczywiście może być wymaganae zainstalowanie Microsoft Access Database Engine 2010 Redistributable i wywołanie w odpowiedniej bitowości (takiej jak engine): dla 32 bitów:

%windir%\SysWoW64\wscript.exe c:\roboczy\scheduler.vbs
0

Panczo, rozumiem, że kwerendy będą pracowały, ale plik nie zostanie otwarty. Tylko pliki są duże na granicy dostępnych rozmiarów, Przy każdym zamknięciu się kompaktują. czy przy rozwiązaniu ze skryptem, pliki nie będą "puchnąć"?

1

Generalnie jezeli pracujesz na granicy rozmiaru to warto przejśc na inny silnik.

Pliki będa puchnąć, ale nic nie stoi na przeszkodzie aby z poziomu vbscriptu zrobić kompktowanie bazy:

connStr = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source="
Set objConn = CreateObject("ADODB.Connection")

'AKTUALIZACJA DANYCH W PLIKU #1

plik = "c:\roboczy\baza1.accdb"
'Open Connection
objConn.open connStr & plik

with objConn
    .Execute "00_czysci tabela_moje_kody"
    .Execute "00_aktualizuje tabela_moje_kody"
    .Execute "00_czysci tabela_sprzed_dzienna_30"
    .Execute "00_aktualizuje tabela_sprzed_dzienna_30"
    .Execute "00_tworzy tabela_regulacji_mag_surowe"
    .Execute "00_czysci tabela_MEA_teraz"
    .Execute "00_nowe_aktualizuje tabela_MEA_teraz"
    .Execute "00_czysci tabela_MEA"
    .Execute "00_nowe_dodaje tabela_MEA_his"
    .Execute "00_nowe_dodaje tabela_MEA_teraz"
    .Execute "00_nowe_czysci tabela_sprzed_surowe_teraz"
    .Execute "00_nowe_aktualizuje tabela_sprzed_surowe_teraz"
    .Execute "00_nowe_czysci tabela_sprzed_surowe"
    .Execute "00_nowe_dodaje sprzed_surowe_his"
    .Execute "00_nowe_dodaje sprzed_surowe_teraz"
end with

objConn.Close
compactACCDB plik
'AKTUALIZACJA DANYCH W PLIKU #2

plik = "c:\roboczy\baza2.accdb"
'Open Connection
objConn.open connStr & plik

with objConn
    .Execute "zapytanie do bazy 2"

end with

objConn.Close
compactACCDB plik
'AKTUALIZACJA DANYCH W PLIKU #3

plik = "c:\roboczy\baza3.accdb"
'Open Connection
objConn.open connStr & plik

with objConn
    .Execute "zapytanie do bazy 3"

end with

objConn.Close
compactACCDB plik

Sub compactACCDB (p)
Dim objFSO
Dim objEngine
Dim strLckFile
Dim strSrcName
Dim strDstName

strLckFile =  Replace(p,".accdb",".laccdb")
strSrcName =  p
strDstName =  Replace(p,".accdb","_compacted.accdb")
strBackup =  Replace(p,".accdb","_backup.accdb")


Set objEngine = CreateObject("DAO.DBEngine.120")

Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not (objFSO.FileExists(strLckFile)) Then
    If (objFSO.FileExists(strBackup)) Then
        objFSO.DeleteFile strBackup
    End If
    If (objFSO.FileExists(strDstName)) Then
        objFSO.DeleteFile strDstName
    End If
    objFSO.CopyFile strSrcName, strBackup

    ''dbVersion120 = 128 
    objEngine.CompactDatabase strSrcName, strDstName, , 128

    objFSO.DeleteFile strSrcName
    objFSO.MoveFile strDstName, strSrcName
End If 'LckFile
end Sub

Na podstawie: https://stackoverflow.com/questions/3133738/why-cant-i-use-compactdatabase-in-dao-dbengine-36-using-vbscript

0

Niestety to będzie trudniejsze niż myślałem. Próby ze skryptem dały błąd jak poniżej. Linia 11 znak 5 zaczyna się od

.Execute "01_czysci tabela_moje_kody"

komunikat_vbs.png

1

Problemem jest spacja w nazwie 01_czysci tabela_moje_kody zmień na 01_czysci_tabela_moje_kody w kodzie i pliku accdb nazwę obiektu

0

działa, niestety dzisiaj nie przetestuje całości, dokończę w piątek. Na tą chwilę dziękuję

0

rozwiązanie z wykorzystaniem skryptu nie radzi sobie w sytuacji, kiedy uruchamiam kwerendę, która ma utworzyć nową tabelę, a ta tabela już wcześniej była utworzona. Access w takiej sytuacji informuję, że uruchomienie kwerendy spowoduję usuniecie poprzedniej tabeli i czeka na potwierdzenie. Niestety z poziomo skryptu wywala błąd. Jeżeli wcześniej ręcznie usunę tą tabelę to przejdzie bez problemu. Jest sposób na uruchomienie Modułu w którym będę miał kod jak poniżej?

DoCmd.DeleteObject acTable, "02_prognoza_fin"
0

Odpowiednikiem kodu SQL który masz w poście, jest taki SQL:

drop table 02_prognoza_fin
0

Panczo, dziękuję. Czuje się jakbym chciał się nauczyć jeździć rowerem, a nauczyłem się prowadzić rakiety!!! Rozwiązanie działa bez zarzutu. W kodzie finalnym zrezygnowałem z kopii zapasowej.

Bedzie dużym nadużyciem jak poproszę o wytłumaczenie części kodu, której nie rozumiem? Otóż nie wiem jak posługiwać się tym zapisem:

strLckFile =  Replace(p,".accdb",".laccdb")
strSrcName =  p
strDstName =  Replace(p,".accdb","_compacted.accdb")
strBackup =  Replace(p,".accdb","_backup.accdb")

czyli jak działać na plikach bez podawania ich nazwy, tylko jako zdefiniowaną zmienną. Od razu zaznaczę, że jestem bardzo początkujący jeżeli chodzi o rozwiązania automatyzacji od strony kodu.

0

Do funkcji kompaktującej baze przekazujesz ściezke pliku (p), tak naprawdę kompaktowanie to w dużym skrócie i uproszczeniu kopiowanie pliku porządkujące kolejnośc danych w plik i pomijanie "pustych" danych.

Wiec musimy poznać sciezke do pliku laccdb , nowej kopii i backupu.
Funkcja replace, zamienia w podanym ciągu jeden ciąg znakow na drugi, czyli:
Replace(p,".accdb",".laccdb") znaczy tyle: w ciągu c:\roboczy\baza1.accdb znajdź .accdb i podmień na .laccdb i analogicznie dla reszty, czyli wartości po zmianach będą takie:

strLckFile =  "c:\roboczy\baza1.laccdb"
strDstName =  "c:\roboczy\baza1_compacted.accdb"
strBackup =  "c:\roboczy\baza1_backup.accdb"
0

wrócę do tematu, skrypt często zwraca błąd na różnych liniach ale zawsze przy tej samej instrukcji

objConn.open connStr & plik

błąd nie wynika ze złej części kodu, bo po uruchomieniu skryptu ponownie bez wykonania żadnych korekt, przechodzi poprawnie. Z czego może wynikać błąd otwarcia pliku i czy obsługą błędu on Error dam radę wykonać poprawnie skryp, jeżeli on Error będzie dobrym rozwiązaniem to wykonać cały skrypt od nowa czy cofnąć się tylko o jedną linie?

0

Komunikat błędu?

0

jak na złość, żaden nie chce wyjść. Jak tylko się pojawi to zapiszę.

0

jednak błędy wychodzą w różnych miejscach i przy różnych instrukcjach, ale zawsze kolejne uruchomienie skryptu bez modyfikacji powoduje, że przejdzie cały bez błędu. Ekran błędu poniżej

.Execute "aktualizuje_tabela_do_analizy"

komunikat_12062019.png

0

..... i kolejny

objConn.open connStr & plik

komunikat_12062019_v2.png

0

... oraz kolejny

    .Execute "04_dodaje_sprzed_surowe_his"

komunikat_12062019_v3.png

0

Pytanie to jak to jest uruchamiane, moze wcześniejsze uruchomienie się nie zakończyło i sta te błedy?

0

w nocy w pierwszej kolejności komputer się restartuje, żeby odświeżyć źródła danych i wznowić ewentualne połączenia. Po restarcie dopiero uruchamiane są skrypty. Przy pierwszym uruchomieniu raczej nie ma możliwości, żeby nie były zakończone poprzednie próby uruchomienia.

0

To po restarcie usunąłbym,jeszcze pliki laccb aby mieć pewność, że żadnej blokady na accdb nie ma

0

.... a może na początku każdego skryptu usuwać *.laccb

0

przetestuj, mnie trudno coś więcej powiedzieć bo trzeba y było znać dokladnie co w tych plikach jest

0
Panczo napisał(a):

Generalnie jezeli pracujesz na granicy rozmiaru to warto przejśc na inny silnik.

Jak przejść na inny silnik? W tej chwili używam accessa, do ściągnięcia danych z serwerów. uruchamiane jest w nocy, kiedy sieć nie jest obciążona. Magazynuje je na dysku w plikach *.accdb. Taki format i miejsce powoduję, że mam łatwy i bardzo szybki dostęp do danych z poziomu excel. Tabele przestawne, wykresy, raporty, wszystko z poziomu excela, bez potrzeby magazynowania tych danych w formacie *.xlsx. Minus taki, że pracuję na prawie maksymalnych rozmiarach. Na przełomie roku kalendarzowego jest usuwany/archiwizowany najstarszy rok i tabele się zmniejszają, ale w drugiej połowie roku i pod koniec już jest ciasno.

Jest inny sposób na przygotowanie tych danych?

1

Np. darmowy SQL Server Express - Dane ciągniesz bezpośrednio do Excela jak teraz z Accessa. Wszystkie operacje ETL robisz w SSIS i temat masz ślicznie ogarnięty.

0

Cześć, wracam do tematu, uruchamiam kwerendy ze skryptu VBs, ale problem polega na tym, że serwer źródłowy, nie zawsze jest dostępny. Czyli potrzebuje w pierwszej kolejności sprawdzić dostępność połączenia, a łącze się przez ODBC, sterownik oracle. Pytanie czy z poziomu windows 7 (harmonogram zadań lub inne rozwiązanie) mogę w jakiś sposób sprawdzić połączenie, a dopiero jeżeli połączenie dostępne puścić skrypt?

0

A nie prościej w skrypcie zestawić połaczenie ado i obsłuzyć bład jeśli metoda open się nie powiedzie?

0

dla amatora stanowi to pewien problem,

dim DB
dim RS
On Error Resume Next
	Set DB = CreateObject("ADODB.Connection")
	DB.Open "DSN=xxxx;UID=yyyy;;"
If Err then
	co tu powinno być?
Else
	mój kod
end if

Z powyższego kodu, da się coś zrobić, co powinno być w miejscu if err then? Pożądany efekt będzie taki, że jak sprawdzi, że nie ma połączenia musi poczekać np 20 minut i sprawdzić ponownie i tak do czasu aż źródło się pojawi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1