Access
 sql >> Baza danych >  >> RDS >> Access

Wstawianie zbiorcze lub aktualizacja tabel z polami załączników

Od 2010 r. program Access obsługuje typ danych Załączniki, który na pierwszy rzut oka wydaje się wygodną funkcją do przechowywania małych obrazów lub plików. Jednak szybkie wyszukiwanie w Google zwykle pokazuje, że najlepiej ich unikać. Wszystko sprowadza się do tego, że typ danych Załączniki jest w rzeczywistości polem wielowartościowym (MVF), a te wiążą się z kilkoma problemami. Po pierwsze, nie możesz używać zapytań do wstawiania lub aktualizowania kilku rekordów za jednym razem. Rzeczywiście, wszelkie tabele zawierające taki typ danych zmuszają do wykonania dużej ilości kodu i tylko z tego powodu unikamy normalnego używania takich typów danych.

Jest jednak problem. Uwielbiamy używać galerii obrazów i motywów, które zależą od tabeli systemowej MSysResources który niestety wykorzystuje typy danych załączników. Stworzyło to problem z zarządzaniem zasobami w naszej standardowej bibliotece, ponieważ chcemy użyć MSysResources ale nie możemy łatwo zaktualizować lub wstawić ich zbiorczo.

Typ danych załącznika (jak również MVF) zmusza do korzystania z programowania „wiersz po wierszu” podczas pracy z polem MVF, jest to dwójka z polem Załączniki, ponieważ musiałbyś użyć LoadFromFile lub SaveToFile metody. Microsoft ma artykuł z przykładami na temat tych metod. Dlatego musisz wchodzić w interakcję z systemem plików podczas dodawania nowych rekordów. Nie zawsze pożądane we wszystkich sytuacjach. Teraz, jeśli kopiujemy z jednej tabeli do drugiej, możemy uniknąć odbijania się od systemu plików, wykonując coś takiego:

Dim SourceParentRs As DAO.Recordset2
Dim SourceChildRs As DAO.Recordset2
Dim TargetParentRs As DAO.Recordset2
Dim TargetChildRs As DAO.Recordset2
Dim SourceField As DAO.Field2

Set SourceParentRs = db.OpenRecordset("TableWithAttachmentField", dbOpenDynaset)
Set TargetParentRs = db.OpenRecordset("AnotherTableWithAttachmentField", dbOpenDynaset, dbAppendOnly)

Do Until SourceParentRs.EOF
  TargetParentRs.AddNew
  For Each SourceField In SourceParentRs.Fields
    If SourceField.Type <> dbAttachment Then
      TargetParentRs.Fields(SourceField.Name).Value = SourceField.Value
    End If
  Next

  TargetParentRs.Update 'Must save record first before can edit MVF fields
  TargetParentRs.Bookmark = TargetParentRs.LastModified
  Set SourceChildRs = SourceParentRs.Fields("Data").Value
  Set TargetChildRs = TargetParentRs.Fields("Data").Value
  Do Until SourcechildRs.EOF
    TargetChildRs.AddNew
    Const ChunkSize As Long = 32768
    Dim TotalSize As Long
    Dim Offset As Long

    TotalSize = SourceChildRs.Fields("FileData").FieldSize
    Offset = TotalSize Mod ChunkSize
    TargetChildRs.Fields("FileData").AppendChunk(SourceChildRs.GetChunk(0, Offset)
    Do Until Offset > TotalSize
      TargetChildRs.Fields("FileData").AppendChunk(SourceChildRs.GetChunk(Offset, ChunkSize)
      Offset = Offset + ChunkSize
    Loop
    TargetChildRs.Update
    SourceChildRs.MoveNext
  Loop
  TargetParentRs.Update
  SourceParentRs.MoveNext
Loop

Święta pętla, batman! To dużo kodu, a wszystko po to, aby skopiować załączniki z jednej tabeli do drugiej. Mimo że nie odbijamy się od systemu plików, jest on również bardzo powolny. Z naszego doświadczenia wynika, że ​​tabela z 1000 rekordów zawierających jeden załącznik może zająć minuty tylko do przetworzenia. Teraz jest to dość przesadne, biorąc pod uwagę rozmiar. Stół z przystawkami nie jest taki duży. Właściwie zróbmy eksperyment. Zobaczmy, co się stanie, jeśli skopiuję i wkleję za pomocą arkusza danych:

Tak więc kopiowanie i wklejanie jest praktycznie natychmiastowe. Oczywiście kod używany przez wklejanie nie jest tym samym kodem, którego używalibyśmy w VBA. Wierzymy jednak, że jeśli możemy to zrobić interaktywnie, możemy to zrobić również w VBA. Czy możemy powtórzyć szybkość interaktywnego wklejania w VBA? Okazuje się, że odpowiedź brzmi:tak, możemy!

Przyspiesz dzięki…. XML?

Co zaskakujące, najszybszą metodą kopiowania danych, w tym załączników, jest wykorzystanie plików XML. Przyznam, że nie sięgam po pliki XML, chyba że jako obejście ograniczeń. Średnio pliki XML są stosunkowo wolne w stosunku do innych formatów plików, ale w tym przypadku XML ma jedną ogromną zaletę; nie ma problemu z opisaniem MVF. Stwórzmy plik XML i zbadajmy możliwości, jakie otrzymujemy dzięki importowaniu/eksportowaniu pliku XML.

Po zwykłym oknie dialogowym kreatora eksportu, aby ustawić ścieżkę do zapisania pliku XML, pojawi się takie okno dialogowe:

Jeśli następnie klikniemy przycisk „Więcej opcji…”, zamiast tego pojawi się następujące okno dialogowe:

Z tego okna dialogowego widzimy jeszcze kilka wskazówek dotyczących tego, co jest możliwe; mianowicie:

  • Mamy możliwość wyeksportowania całej tabeli lub tylko jej podzbioru przez zastosowanie filtra
  • Możemy przekształcić wyjście XML.
  • Możemy opisać schemat oprócz zawartości tabeli.

Uważam, że najlepiej jest osadzić schemat; domyślnie jest eksportowane, ale jako osobny plik. Jednak może to być podatne na błędy i mogą zapomnieć o dołączeniu pliku XSD do pliku XML. Można to zmienić za pomocą pokazanej zakładki schematu:

Zakończmy eksportowanie i rzućmy okiem na dane wynikowego pliku XML.

Zwróć uwagę, że załączniki są opisane w Dane zawartość poddrzewa i pliku jest zakodowana w base-64. Spróbujmy zaimportować plik XML. Po przejściu przez kreatora importu pojawi się następujące okno dialogowe:

Zwróć uwagę na następujące funkcje:

  • Podobnie jak w przypadku eksportu, mamy możliwość przekształcenia XML.
  • Możemy kontrolować, czy importować strukturę, dane, czy jedno i drugie

Jeśli następnie zakończymy importowanie pliku XML, okaże się, że jest to tak samo szybkie, jak wykonana przez nas operacja kopiowania i wklejania.

Teraz wiemy, że istnieje lepsza ścieżka do kopiowania kilku rekordów z załącznikami. Ale w tej sytuacji chcemy to zrobić programowo, a nie interaktywnie. Czy możemy zrobić to samo, co właśnie zrobiliśmy? Ponownie, odpowiedź brzmi:tak. Istnieje wiele sposobów na zrobienie tego samego, ale myślę, że najłatwiejszą metodą jest użycie 3 nowych metod, które zostały dodane do Aplikacji obiekt od Access 2010:

  • Eksport XML metoda
  • TransformXML metoda
  • Import XML metoda

Zauważ, że ExportXML metoda obsługuje eksportowanie z różnych obiektów. Ponieważ jednak celem jest tutaj możliwość masowego kopiowania lub aktualizowania rekordów tabeli z polami załączników, najlepszym typem obiektu, którego możemy użyć, jest zapisane zapytanie. Dzięki zapisanemu zapytaniu możemy kontrolować, które wiersze mają zostać wstawione lub zaktualizowane, a także możemy kształtować wynik. Jeśli spojrzysz na projekt schematu MSysResources tabela poniżej:

Istnieje potencjalny problem. Za każdym razem, gdy używamy motywów lub obrazów, odwołujemy się do przedmiotu według nazwy, a nie identyfikatora. Jednak Nazwa kolumna nie jest unikatowa i nie jest kluczem podstawowym tabeli. Dlatego kiedy dodajemy lub aktualizujemy rekordy, chcemy dopasować na Nazwie kolumna, a nie Id kolumna. Oznacza to, że podczas eksportu prawdopodobnie nie powinniśmy dołączać Id kolumnę i powinniśmy wyeksportować tylko unikalną listę Nazwy aby upewnić się, że zasoby nie zmienią się nagle z „Open.png” na „Close.png” lub coś głupiego.

Następnie utworzymy zapytanie, które będzie działać jako źródło rekordów, które chcemy zaimportować do MSysResources stół. Zacznijmy od tego kodu SQL, aby zademonstrować filtrowanie do podzbioru rekordów:

SELECT e.Data, e.Extension, e.Name, e.Type
FROM Example AS e
WHERE e.Name In ("blue","red","green");

Następnie zapiszemy go jako qryResourcesExport . Następnie możemy napisać kod VBA, aby wyeksportować XML:

Application.ExportXML _
  ObjectType:=acExportQuery, _
  DataSource:="qryResourcesExport", _
  DataTarget:="C:\Path\to\Resources.xml", _
  OtherFlags:=acEmbedSchema

To emuluje eksport, który pierwotnie wykonaliśmy interaktywnie.

Jeśli jednak następnie zaimportujemy wynikowy XML, mamy tylko możliwość dołączenia danych do istniejącej tabeli. Nie możemy kontrolować, do której tabeli zostanie dodany; znajdzie tabelę lub tabelę zapytań o tej samej nazwie (np. qryResourcesExport i dołącz rekordy do tego zapytania. Jeśli zapytanie można aktualizować, nie ma problemu i zostanie wstawione do Przykładu na którym opiera się zapytanie. Ale co, jeśli używane przez nas zapytanie źródłowe nie może być aktualizowane lub może nie istnieć? W obu przypadkach nie moglibyśmy zaimportować pliku XML bez zmian. Import może się nie powieść lub zakończyć tworzenie nowej tabeli o nazwie qryResourcesExport co nam nie pomaga. A co z przypadkiem kopiowania danych z Przykładu do MSysResources ? Nie chcemy dołączać danych do Przykładu tabela.

To właśnie tam TransformXML metoda przychodzi na ratunek. Pełna dyskusja na temat pisania transformacji XML wykracza poza zakres, ale powinieneś być w stanie znaleźć obszerne zasoby dotyczące pisania arkusza stylów XSLT opisującego transformację. Istnieje również kilka narzędzi online, których możesz użyć do walidacji swojego XSLT. Tu jest jeden. W prostym przypadku, w którym chcemy tylko kontrolować, do której tabeli plik XML powinien dołączać rekordy, możesz zacząć od tego pliku XSLT. Następnie możesz uruchomić następujący kod VBA:

Application.TransformXML _
  DataSource:="C:\Path\to\Resources.xml", _
  TransformSource:="C:\Path\to\ResourcesTransform.xslt", _
  OutputTarget:="C:\Path\to\Resources.xml", _
  WellFormedXMLOutput:=True, _
  ScriptOption:=acEnableScript

Możemy zastąpić oryginalny plik XML przekształconym plikiem XML, który zostanie teraz wstawiony do MSysResources tabeli zamiast do (prawdopodobnie nieistniejącego zapytania/tabeli) qryResourcesExport .

Następnie musimy zająć się aktualizacjami. Ponieważ faktycznie dołączamy nowe rekordy, a MSysResources tabela nie ma żadnych ograniczeń co do zduplikowanych nazw, musimy upewnić się, że wszelkie istniejące rekordy o tych samych nazwach zostaną najpierw usunięte. Można to osiągnąć, pisząc równoważne zapytanie, takie jak:

DELETE FROM MSysResources AS r
WHERE r.Name In ("blue","red","green");

następnie uruchom go najpierw przed uruchomieniem kodu VBA:

Application.ImportXML DataSource:="C:\Path\to\Resources.xml", ImportOptions:=acAppendData

Ponieważ plik XML został przekształcony, ImportXML metoda wstawi teraz dane do MSysResources zamiast oryginalnego zapytania, którego użyliśmy z ExportXML metoda. Określamy, że powinien dołączyć dane do istniejącej tabeli. Jeśli jednak tabela nie istnieje, zostanie utworzona.

Dzięki temu uzyskaliśmy masową aktualizację/wstawienie tabeli z polem załącznika, które jest znacznie szybsze w porównaniu do oryginalnego kodu VBA zestawu rekordów i zestawu rekordów podrzędnych. Mam nadzieję, że to pomoże! Ponadto, jeśli potrzebujesz pomocy przy tworzeniu aplikacji Access, skontaktuj się z nami!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak program Access komunikuje się ze źródłami danych ODBC? Część 1

  2. Dostęp do wyszukiwania komunikatów o numerach błędów

  3. Jak wyeksportować listę połączonych tabel do programu Excel z programu Access 2016

  4. Jak utworzyć pole obliczeniowe w zapytaniu programu Microsoft Access

  5. Co to jest Microsoft Access i do czego go używasz?