sql >> Databáze >  >> RDS >> Access

Hromadné vkládání nebo aktualizace pro tabulky s poli příloh

Od Accessu 2010 podporuje Access datový typ Attachments, který se na první pohled jeví jako pohodlná funkce pro ukládání malých obrázků nebo souborů. Rychlé vyhledávání na Googlu však obvykle ukáže, že je lepší se jim vyhnout. To vše se scvrkává na skutečnost, že datový typ Attachments je ve skutečnosti pole s více hodnotami (MVF) a to přináší několik problémů. Za prvé, nebudete moci používat dotazy k vložení nebo aktualizaci několika záznamů najednou. Všechny tabulky, které obsahují takový datový typ, vás skutečně nutí provádět velké množství kódu a už jen z tohoto důvodu se takové datové typy běžně nepoužíváme.

Nicméně je tu problém. Rádi používáme galerii obrázků a motivy, které závisí na systémové tabulce MSysResources který bohužel používá datové typy příloh. To způsobilo problém se správou zdrojů v naší standardní knihovně, protože chceme používat MSysResources ale nemůžeme je snadno aktualizovat nebo vložit hromadně.

Datový typ přílohy (stejně jako MVF) vás nutí používat programování „řádek po agonizujícím řádku“ při práci s polem MVF, je to dvojka s polem Přílohy, protože byste museli použít LoadFromFile nebo Uložit do souboru metody. Microsoft má článek s příklady o těchto metodách. Při přidávání nových záznamů tedy musíte interagovat se souborovým systémem. Ne vždy ve všech situacích žádoucí. Nyní, pokud kopírujeme z jedné tabulky do jiné tabulky, můžeme se vyhnout skákání přes souborový systém tím, že uděláme něco jako:

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

Holy looping, batmane! To je spousta kódu, vše jen pro kopírování příloh z jedné tabulky do druhé. I když neskáčeme přes souborový systém, je také velmi pomalý. Podle našich zkušeností může tabulka s 1000 záznamy obsahující jednu přílohu trvat minut jen zpracovat. Nyní je to docela předimenzované, když vezmete v úvahu velikost. Stůl s přílohami není tak velký. Ve skutečnosti udělejme experiment. Podívejme se, co se stane, když zkopíruji a vložím přes datový list:

Kopírování a vkládání je tedy prakticky okamžité. Je zřejmé, že kód použitý při vkládání není stejný kód, který bychom použili ve VBA. Jsme však přesvědčeni, že když to dokážeme interaktivně, můžeme to udělat i ve VBA. Můžeme replikovat rychlost interaktivního vkládání ve VBA? Odpověď zní ano, můžeme!

Zrychlete pomocí…. XML?

Překvapivě metoda, která poskytuje nejrychlejší způsob kopírování dat, včetně příloh, je pomocí souborů XML. Přiznám se, že nesahám po souborech XML, s výjimkou řešení omezení. V průměru jsou soubory XML relativně pomalé vůči jiným formátům souborů, ale v tomto případě má XML jednu obrovskou výhodu; nemá problém s popisem MVF. Pojďme vytvořit soubor XML a prozkoumat možnosti, které získáváme při importu/exportu souboru XML.

Po obvyklém dialogovém okně průvodce exportem pro nastavení cesty k uložení souboru XML se nám zobrazí následující dialog:

Pokud poté klikneme na tlačítko „Další možnosti…“, místo toho se zobrazí toto dialogové okno:

Z tohoto dialogu vidíme několik dalších vodítek o tom, co je možné; jmenovitě:

  • Máme možnost exportovat celou tabulku nebo pouze podmnožinu tabulky použitím filtru
  • Můžeme transformovat výstup XML.
  • Schéma můžeme popsat kromě obsahu tabulky.

Zjistil jsem, že nejlepší je vložit schéma; výchozí je exportovat jej, ale jako samostatný soubor. To však může být náchylné k chybám a mohou zapomenout zahrnout soubor XSD do souboru XML. Toto lze změnit na zobrazené kartě schématu:

Dokončeme export a stručně se podíváme na data výsledného souboru XML.

Všimněte si, že přílohy jsou popsány v části Data podstrom a obsah souboru je kódován base-64. Zkusme importovat soubor XML. Po procházení průvodce importem se nám zobrazí tento dialog:

Všimněte si následujících funkcí:

  • Stejně jako u exportu máme možnost transformovat XML.
  • Můžeme řídit, zda importovat strukturu, data nebo obojí

Pokud poté dokončíme import souboru XML, zjistíme, že je stejně rychlý jako operace kopírování a vkládání, kterou jsme provedli.

Nyní víme, že existuje lepší cesta ke kopírování několika záznamů s přílohami. Ale v této situaci to chceme dělat programově, spíše než interaktivně. Můžeme udělat to samé, co jsme právě udělali? Odpověď je opět ano. Existuje několik způsobů, jak udělat totéž, ale myslím, že nejjednodušší je použít 3 nové metody, které byly přidány do Aplikace objekt od Accessu 2010:

  • ExportXML metoda
  • TransformXML metoda
  • Import XML metoda

Všimněte si, že ExportXML metoda podporuje export z různých objektů. Protože je zde cílem umět hromadně kopírovat nebo aktualizovat záznamy tabulky s poli příloh, je pro nás nejlepším typem objektu uložený dotaz. Pomocí uloženého dotazu můžeme řídit, které řádky se mají vložit nebo aktualizovat, a také můžeme tvarovat výstup. Pokud se podíváte na návrh schématu MSysResources tabulka níže:

Existuje potenciální problém. Kdykoli používáme motivy nebo obrázky, odkazujeme na položku jménem, ​​nikoli podle ID. Nicméně Název sloupec není jedinečný a není primárním klíčem tabulky. Proto, když přidáváme nebo aktualizujeme záznamy, chceme se shodovat s Jméno sloupec, nikoli ID sloupec. To znamená, že když exportujeme, pravděpodobně bychom neměli zahrnout Id a měli bychom exportovat pouze jedinečný seznam Název aby se zajistilo, že zdroje náhle nepřejdou z „Open.png“ na „Zavřít.png“ nebo něco hloupého.

Poté vytvoříme dotaz, který bude sloužit jako zdroj pro záznamy, které chceme importovat do MSysResources stůl. Začněme s tímto SQL, abychom demonstrovali filtrování až na podmnožinu záznamů:

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

Poté jej uložíme jako qryResourcesExport . Poté můžeme napsat kód VBA pro export XML:

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

To emuluje export, který jsme původně provedli interaktivně.

Pokud však následně importujeme výsledné XML, máme pouze možnost připojit data k existující tabulce. Nemůžeme kontrolovat, do které tabulky se to připojí; najde tabulku nebo tabulku dotazu se stejným názvem (např. qryResourcesExport a připojit záznamy do tohoto dotazu. Pokud je dotaz aktualizovatelný, není problém a vloží se do Příklad na kterém je dotaz založen. Ale co když zdrojový dotaz, který používáme, není aktualizovatelný nebo nemusí existovat? V obou případech bychom nebyli schopni importovat soubor XML tak, jak je. Může se stát, že import selže nebo se vytvoří nová tabulka s názvem qryResourcesExport což nám nepomůže. A co případ kopírování dat z Příkladu na MSysResources ? Nechceme přidávat data k Příkladu tabulka.

Zde se nachází TransformXML metoda přichází na záchranu. Úplná diskuse o tom, jak napsat transformaci XML, je nad rámec, ale měli byste být schopni najít dostatek zdrojů o tom, jak napsat šablonu stylů XSLT k popisu transformace. Existuje několik online nástrojů, které můžete použít také pro ověření vašeho XSLT. Zde je jeden. Pro jednoduchý případ, kdy chceme pouze řídit, do které tabulky má soubor XML připojovat záznamy, můžete začít s tímto souborem XSLT. Poté můžete spustit následující kód 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

Můžeme nahradit původní soubor XML transformovaným souborem XML, který se nyní vloží do MSysResources tabulky spíše než do (pravděpodobně neexistujícího dotazu/tabulky) qryResourcesExport .

Pak musíme zpracovat aktualizace. Protože ve skutečnosti připojujeme nové záznamy a MSysResources tabulka nemá žádná omezení na duplicitní názvy, musíme zajistit, aby byly všechny existující záznamy se stejnými názvy nejprve odstraněny. Toho lze dosáhnout napsáním ekvivalentního dotazu jako takto:

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

pak jej nejprve spusťte před spuštěním kódu VBA:

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

Protože byl soubor XML transformován, ImportXML metoda nyní vloží data do MSysResources namísto původního dotazu, který jsme použili s ExportXML metoda. Určujeme, že má připojovat data do existující tabulky. Pokud však tabulka neexistuje, bude vytvořena.

A díky tomu jsme dosáhli hromadné aktualizace/vložení tabulky s polem přílohy, která je mnohem rychlejší ve srovnání s původním kódem VBA sady záznamů a podřízených záznamů. Doufám, že to pomůže! Také, pokud potřebujete pomoc s vývojem aplikací Access, neváhejte nás kontaktovat!


  1. Běžné úkoly Postgres na CentOS 7

  2. Skalární vkládání UDF v SQL Server 2019

  3. Jak mohu použít dotaz se zástupným symbolem uvnitř uvozovek? (perl / postgresql)

  4. Jaký je rozdíl mezi Float a Numeric/Decimal na SQL Server - SQL Server / T-SQL výukový program, část 33