vbamania.pl
login:
hasło:
 
  *Rejestracja *Zapomniane hasło
 Dziś jest czwartek, 02 maja 2024 roku.
Ustaw jako stronę startową Ulubione Napisz
PowrótPowrót do serwisu  RegulaminRegulamin rssRSS

  tytuł wątku:
Wątki dyskusji

wyszukiwanie danych w zamkniętym pliku Excel


otwartyotwarty rozpoczął: VBAmator postów: 18



napisał: VBAmator
postów: 67


umieszczony:
22 marca 2018
15:21

  
Kod zaadaptowany, działa szybko. Bardzo dziękuję za pomoc.

Hahaha, skąd pomysł na nazwę pliku w przykładzie? Skądinąd bardzo trafiony...
napisał: Trebor
postów: 1209


umieszczony:
21 marca 2018
21:00

edytowany:
21 marca 2018
21:19

  
Z tego co czytam w Internecie to jest to duży problem. Podają jakieś tam rozwiązania ale dość skomplikowane. Sprawdź ile będzie się u Ciebie wykonywać kopia skoroszytu i jej usunięcie. Coś w rodzaju:
Sub kopia()
FileCopy "C:\......\motyle.xlsx", "C:\........\motyle2.xlsx"

Kill "C:\........\motyle2.xlsx"
End Sub



O ile pamiętam to kopię pliku musisz robić w obrębie jednego dysku.

Po jakimś czasie: zdaje się, że z otwartego skoroszytu kopii nie da się zrobić taką metodą.
I jeszcze później: spróbuj jeszcze tak:
Set objFso = CreateObject("Scripting.FileSystemObject")

objFso.CopyFile "C:........\motyle.xlsx", "C:\......\motyle2.xlsx"
Set objFso = Nothing

Kill "C:\.......\motyle2.xlsx"

napisał: VBAmator
postów: 67


umieszczony:
21 marca 2018
15:24

  
Rozumiem, że opcja pozyskania danych i nieotwierania pliku pomimo wszystko, nie wchodzi w grę.

A zatem najlepsza będzie opcja "kopia-dane-kill kopia". Za wszelką cenę chcę uniknąć otwierania pliku ponieważ waży sporo, otwiera się kilkanaście sekund i ma obfite workbook_open().
napisał: Trebor
postów: 1209


umieszczony:
20 marca 2018
18:24

  
Napisz jak byś chciał aby zareagowało makro. Ma odpuścić ściąganie danych, czy też zamknąć skoroszyt źródłowy po ściągnięciu danych czy jeszcze coś innego, a może wykonać kopię skoroszytu źródłowego ściągnąć dane i usunąć kopię?
napisał: VBAmator
postów: 67


umieszczony:
20 marca 2018
10:56

  
Przepraszam Trebor, ale nie zrozumieliśmy się. Pozwolę sobie wytłumaczyć innymi słowami.

Założeniem makra było pobranie danych z pliku źródłowego TEST.xlsm bez jego otwierania. Makro jest błyskawiczne i spełnia podstawowe założenie
pod warunkiem, że plik źródłowy nie jest przez nikogo używany/otwarty w momencie pozyskiwania danych.
Jeśli pracuje na nim inny użytkownik, to poniższa linijka powoduje otwarcie pliku źródłowego (oczywiście tylko do odczytu) co wychodzi poza nasze podstawowe założenie.
oCn.Open strConnectionString


W ADO mam jeszcze biały pas więc bardzo proszę o pomoc.
napisał: Trebor
postów: 1209


umieszczony:
19 marca 2018
16:16

  
Należy określić pełną ścieżkę zapisu np.
'============================================================
With ThisWorkbook.Sheets(1)
 For nActRow = 0 To nRowCount
  
   If xArray(0, nActRow) = "silnik" Then '--------------------
        .Cells(1, 1) = xArray(0, nActRow)
        Licznik_kolumn = 1
        For wiersz = nActRow - 2 To nActRow - 1
            Licznik_wiersz = Licznik_wiersz + 1
                For kolumna = 1 To nColCount
                    Licznik_kolumn = Licznik_kolumn + 1
                  .Cells(Licznik_wiersz, Licznik_kolumn) = xArray(kolumna, wiersz)
                Next kolumna
                Licznik_kolumn = 1
        Next wiersz
    Exit Sub 'zakładam że silnik występuje raz
   End If
 Next
 End With



ThisWorkbook oznacza skoroszyt w którym jest makro
napisał: VBAmator
postów: 67


umieszczony:
19 marca 2018
13:41

  
Manual/Automatic pomogło. Nie wiedziałem, że działa to na wszystkie otwarte okna.

Pojawił się jednak kolejny problem. Okazało się przypadkowo, że jeżeli plik źródłowy jest otwarty przez innego użytkownika w trakcie działania makra to linijka:
oCn.Open strConnectionString


powoduje otwarcie w/w pliku. W rezultacie makro swoje zadanie wykonuje w otworzonym pliku a nie w pliku wynikowym. Jeżeli plik źródłowy jest zamknięty to wszystko działa poprawnie.
Rozumiem, że da się to uwarunkować?
napisał: Trebor
postów: 1209


umieszczony:
17 marca 2018
15:18

  
Być może w komputerze brakuje pamięci lub procesora.
Jednak bardziej prawdopodobne, że masz w skoroszytach wiele formuł, formuły tablicowe lub formuły odnoszące się do dużych zakresów. Na początku makra możesz przełączyć aplikację w tryb ręcznego przeliczania formuł:
Application.Calculation = xlCalculationManual


Na końcu makra przełącz na obliczanie automatyczne.
Napisz czy pomogło.
napisał: VBAmator
postów: 67


umieszczony:
16 marca 2018
13:34

  
Niestety myliłem się. Wszystkie wersje działają błyskawicznie.
Spowolnienie powodują inne pliki Excel otwarte w tym samym czasie. Często obserwuję spowalnianie makr w obecności innych ActiveWindow.
To od czegoś zależy? Może da się ten problem wyeliminować?
napisał: VBAmator
postów: 67


umieszczony:
16 marca 2018
10:58

  
Trafiłeś w sedno. Faktycznie ten kawałek z zamianą wartości mulił. Nawet obejście tablicą, które w końcu sam wypociłem nie pomagało.
W tej chwili niezależnie od updatingu w sekundę.
Bardzo dziękuję za pomoc.
napisał: Trebor
postów: 1209


umieszczony:
15 marca 2018
16:30

edytowany:
15 marca 2018
16:31

  
Pomysł jest bardzo dobry. Jednak dla kilku zapisywanych danych różnica w czasie nie powinna aż tak znacząca. Jeśli wyłączanie odświeżania nie pomaga to może problem tkwi w konwersji danych. Spróbuj podmienić część kodu pomiędzy zielonymi liniami. Liczby przestaną być liczbami a daty datami, ale będziemy wiedzieć czy to jest ewentualna przyczyna spowalniania wykonania makra.
'============================================================

 For nActRow = 0 To nRowCount
  
   If xArray(0, nActRow) = "silnik" Then '--------------------
        Cells(1, 1) = xArray(0, nActRow)
        Licznik_kolumn = 1
        For wiersz = nActRow - 2 To nActRow - 1
            Licznik_wiersz = Licznik_wiersz + 1
                For kolumna = 1 To nColCount
                    Licznik_kolumn = Licznik_kolumn + 1
                  Cells(Licznik_wiersz, Licznik_kolumn) = xArray(kolumna, wiersz)
                Next kolumna
                Licznik_kolumn = 1
        Next wiersz
    Exit Sub 'zakładam że silnik występuje raz
   End If
 Next
'==============================================================



Ile danych jednorazowo makro ściąga?
napisał: VBAmator
postów: 67


umieszczony:
15 marca 2018
11:39

  
Działa poprawnie. Straciła jednak główny atut jakim był czas wykonania. Teraz sekundę zajmuje pobranie jednej wartości a to jest nie do zaakceptowania.
Domyślam się, że przyczyną jest strzelanie w komórki prosto z pętli. ScreenUpdating oczywiście tu nie pomaga.
Zamiast każdorazowego przekazywania danej wypełnił bym nimi tablicę i dopiero potem jednorazowo zaimportował bym całą tablicę do pliku docelowego.
Jeśli to dobry pomysł to bardzo proszę o pomoc na poziomie kodu lub ewentualnie o inne rozwiązanie pozwalające zachować szybki czas wykonania.
napisał: Trebor
postów: 1209


umieszczony:
13 marca 2018
17:48

edytowany:
13 marca 2018
17:48

  
Spróbuj tak:
Option Explicit

Sub ADOGetValue()
Dim sciezka As String, plik As String, Arkusz As String, Zakres As String
Dim wiersz As Long, kolumna As Long, Licznik_wiersz As Long, Licznik_kolumn As Long
Dim arg As String
Dim nRowCount As Long, nColCount As Long
Dim nActRow As Long, nActCol As Long
Dim ArrVal() As Variant
Dim xArray As Variant
Dim xValue As Variant
Dim strConnectionString As String
Dim oCn As Object, oRs As Object
'-----------------------------------------------------------
sciezka = ThisWorkbook.path 'jeśli w tym samym katalogu '|
plik = "Test.xlsm"                                         '|
Arkusz = "Ad1"                                             '|
Zakres = "A1:G1000"                                        '|
'-----------------------------------------------------------
If Right(sciezka, 1) <> "\" Then sciezka = sciezka & "\"
 If Dir(sciezka & plik) = "" Then
  'brak pliku ...
  Exit Sub
 End If

 Set oCn = CreateObject("ADODB.Connection")

 If Val(Application.Version) < 12 Then
    strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                          "Data Source=" & sciezka & plik & ";" & _
                          "Extended Properties=""Excel 8.0;HDR=NO;IMEX=1;"""
 Else
    strConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                          "Data Source=" & sciezka & plik & ";" & _
                          "Extended Properties=""Excel 12.0;HDR=NO;IMEX=1;"""
 End If
 oCn.Open strConnectionString
 arg = "select * from [" & Arkusz & "$" & Zakres & _
      IIf(InStr(Zakres, ":") = 0, ":" & Zakres, "") & "]"

 Set oRs = CreateObject("ADODB.Recordset")
 oRs.Open arg, oCn, 3
 xArray = oRs.getRows
  oRs.Close
 oCn.Close

 Set oRs = Nothing
 Set oCn = Nothing

 nRowCount = UBound(xArray, 2)
 nColCount = UBound(xArray, 1)
 '============================================================

 ReDim ArrVal(1 To nRowCount + 1, 1 To nColCount + 1)

 For nActRow = 0 To nRowCount
  For nActCol = 0 To nColCount
  
   If xArray(nActCol, nActRow) = "silnik" Then '--------------------
        Cells(1, 1) = xArray(nActCol, nActRow)
        Licznik_kolumn = 1
        For wiersz = nActRow - 2 To nActRow - 1
            Licznik_wiersz = Licznik_wiersz + 1
                For kolumna = 1 To nColCount
                    Licznik_kolumn = Licznik_kolumn + 1
                            xValue = xArray(kolumna, wiersz)
                                If IsNumeric(xValue) Then
                                    xValue = CDbl(xValue)
                                ElseIf IsDate(xValue) Then
                                    xValue = CDate(xValue)
                                End If
                    Cells(Licznik_wiersz, Licznik_kolumn) = xValue
                Next kolumna
                Licznik_kolumn = 1
        Next wiersz
    Exit Sub
   End If 'zakładam że silnik występuje raz
  Next
 Next
'==============================================================

End Sub

napisał: VBAmator
postów: 67


umieszczony:
13 marca 2018
14:30

  
nazwa pliku rozmiar
TEST.xlsm 12.93 kB

Faktycznie działa w sekundę. Jeśli chodzi o prędkość bez zarzutu.
Niestety kuleję jeszcze z tablicami więc jedyne co udało mi się zmienić w ramach adaptacji kodu to warunek na element tablicy.
Dostaję wynik w komórce Cells(1,1) ale i tak wypluwa mi w dół zadany zakres.
Function ADOGetValue(path As String, file As String, sheet As String, ref As String)

Dim arg As String
Dim nRowCount As Long, nColCount As Long
Dim nActRow As Long, nActCol As Long
Dim ArrVal() As Variant
Dim xArray As Variant
Dim xValue As Variant
Dim strConnectionString As String
Dim oCn As Object, oRs As Object

If Right(path, 1) <> "\" Then path = path & "\"
 If Dir(path & file) = "" Then
  'brak pliku ...
  ADOGetValue = CVErr(2042)
  Exit Function
 End If

 Set oCn = CreateObject("ADODB.Connection")

 If Val(Application.Version) < 12 Then
    strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                          "Data Source=" & path & file & ";" & _
                          "Extended Properties=""Excel 8.0;HDR=NO;IMEX=1;"""
 Else
    strConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                          "Data Source=" & path & file & ";" & _
                          "Extended Properties=""Excel 12.0;HDR=NO;IMEX=1;"""
 End If
 oCn.Open strConnectionString
 arg = "select * from [" & sheet & "$" & ref & _
      IIf(InStr(ref, ":") = 0, ":" & ref, "") & "]"

 Set oRs = CreateObject("ADODB.Recordset")
 oRs.Open arg, oCn, 3
 xArray = oRs.getRows
 nRowCount = UBound(xArray, 2)
 '============================================================
 nColCount = 0 'UBound(xArray, 1)

 ReDim ArrVal(1 To nRowCount + 1, 1 To nColCount + 1)

 For nActRow = 0 To nRowCount
  For nActCol = 0 To nColCount
   If xArray(nActCol, nActRow) = "silnik" Then '--------------------
    xValue = xArray(nActCol, nActRow)
        If IsNumeric(xValue) Then
         xValue = CDbl(xValue)
        ElseIf IsNull(xValue) Then
         xValue = Empty
        End If
    'ArrVal(nActRow + 1, nActCol + 1) = xValue
    ArrVal(1, 1) = xValue '-------------------------------
    GoTo line1 '----------------------
   End If
  Next
 Next

line1:
 ADOGetValue = ArrVal
'===============================================================
 oRs.Close
 oCn.Close

 Set oRs = Nothing
 Set oCn = Nothing

End Function




W załączniku znajduje się testowy plik źródłowy. Muszę pobrać z niego (bez otwierania) dane (data wysyłki, ilość, itd) np. dla "silnik".
Oczywiście w pliku docelowym będzie analogiczna niewypełniona matryca oczekująca na te dane.
Nie wiem jak to zgrabnie zrobić. Pomóż proszę.
napisał: Trebor
postów: 1209


umieszczony:
12 marca 2018
18:29

  
Zdaje się że największą bolączką jest tutaj szybkość działania. Sprawdź rozwiązanie z ExcelForum. Testowałem na 1000 wierszach i całkiem szybko poszło.
Sub data_from_closed_file()
Range("A1:J1000") = ADOGetValue("C:\......\", "......xlsx", "Ad1", "A1:J1000")
End Sub

Function ADOGetValue(path As String, file As String, sheet As String, ref As String)
' =ADOGetValue(p;f;s;r)
' p - scieżka
' f - nazwa pliku
' s - nazwa arkusza
' r - komórka lub obszar np. "A3", "A1:A10"

    Dim arg As String
    Dim nRowCount As Long, nColCount As Long
    Dim nActRow As Long, nActCol As Long
    Dim ArrVal() As Variant
    Dim xArray As Variant
    Dim xValue As Variant
    Dim strConnectionString As String
    Dim oCn As Object, oRs As Object

    If Right(path, 1) <> "\" Then path = path & "\"

    If Dir(path & file) = "" Then
        'brak pliku ...
        ADOGetValue = CVErr(2042)
        Exit Function
    End If

    Set oCn = CreateObject("ADODB.Connection")

    If Val(Application.Version) < 12 Then
        strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                              "Data Source=" & path & file & ";" & _
                              "Extended Properties=""Excel 8.0;HDR=NO;IMEX=1;"""
    Else
        strConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                              "Data Source=" & path & file & ";" & _
                              "Extended Properties=""Excel 12.0;HDR=NO;IMEX=1;"""
    End If
    oCn.Open strConnectionString
    arg = "select * from [" & sheet & "$" & ref & _
          IIf(InStr(ref, ":") = 0, ":" & ref, "") & "]"

    Set oRs = CreateObject("ADODB.Recordset")

    oRs.Open arg, oCn, 3

    xArray = oRs.getRows

    nRowCount = UBound(xArray, 2)
    nColCount = UBound(xArray, 1)

    ReDim ArrVal(1 To nRowCount + 1, 1 To nColCount + 1)

    For nActRow = 0 To nRowCount

        For nActCol = 0 To nColCount

            xValue = xArray(nActCol, nActRow)

            If IsNumeric(xValue) Then
                xValue = CDbl(xValue)
            ElseIf IsNull(xValue) Then
                xValue = Empty
            End If

            ArrVal(nActRow + 1, nActCol + 1) = xValue

        Next

    Next
    ADOGetValue = ArrVal

    oRs.Close
    oCn.Close

    Set oRs = Nothing
    Set oCn = Nothing

End Function


W Twoim makrze i w tym powyższym pod koniec powstaje tablica ArrVal. Można ją przeszukać i wybrać odpowiednie dane do zapisania w arkuszu.
Czy o to chodziło?
napisał: VBAmator
postów: 67


umieszczony:
12 marca 2018
10:52

edytowany:
12 marca 2018
10:53

  
Sub data_from_closed_file()
Application.ScreenUpdating = False
p = "\\sciezka..."
f = "Excel.xlsx"
S = "Ad1"
zakres = Range(Range("D1").Offset(0, -3), Range("D1").Offset(7, -1)).Address
Range("A1:C8") = GetValue(p, f, S, zakres)

End Sub



Private Function GetValue(path, file, sheet, ref) As Variant

Dim arg As String
Dim nRow, nCol
Dim nRowCount, nColCount
Dim nActRow, nActCol
Dim ArrVal() As Variant

If Right(path, 1) <> "\" Then path = path & "\"
If Dir(path & file) = "" Then
 GetValue = CVErr(2042)
Exit Function
End If
nRow = Range(ref).Row
nCol = Range(ref).Column
nRowCount = Range(ref).Rows.Count
nColCount = Range(ref).Columns.Count
ReDim ArrVal(1 To nRowCount, 1 To nColCount)
For nActRow = 1 To nRowCount
For nActCol = 1 To nColCount
    arg = "'" & path & _
    "[" & file & "]" & _
    sheet & "'!" & _
    "R" & nRow + nActRow - 1 & _
    "C" & nCol + nActCol - 1
    t = ExecuteExcel4Macro(arg)
    ArrVal(nActRow, nActCol) = IIf(t = 0, "", t)
Next
Next
GetValue = ArrVal
End Function

napisał: Trebor
postów: 1209


umieszczony:
9 marca 2018
16:42

  
Zdaj się, że GetValue istnieje w wielu odmianach. Zamieść na forum wariant wykorzystywany przez Ciebie.
napisał: VBAmator
postów: 67


umieszczony:
9 marca 2018
10:58

  
Cześć.
Zaadaptowałem funkcję GetValue do pobierania danych z zamkniętego pliku. Działa wolno ale działa. Niestety jedynie dla zdefiniowanego zakresu lub komórki.
Potrzebuję uzależnić pobieranie od wyszukania odpowiedniej komórki, sprawdzenia dla niej warunku i dopiero wtedy powiedzmy offsetem jakiś określony obszar pobrać.
Czy jest to możliwe?
Byłbym wdzięczny za jakiś przykład dydaktyczny...


<-wstecz  1  dalej->
wszystkich stron: 1


Sortuj posty: z