collapse

* Benutzer Info

 
 
Willkommen Gast. Bitte einloggen oder registrieren. Haben Sie Ihre Aktivierungs E-Mail übersehen?

* Wer ist Online

  • Punkt Gäste: 46
  • Punkt Versteckte: 1
  • Punkt Mitglieder: 3
  • Punkt Benutzer Online:

* Forenstatistik

  • stats Mitglieder insgesamt: 13856
  • stats Beiträge insgesamt: 64954
  • stats Themen insgesamt: 8760
  • stats Kategorien insgesamt: 5
  • stats Boards insgesamt: 16
  • stats Am meisten online: 415

Autor Thema: Recordset und Spezialformular  (Gelesen 466 mal)

Offline crystal

  • Access-Profi
  • **
  • Beiträge: 382
Recordset und Spezialformular
« am: Januar 30, 2018, 14:37:22 »
Liebe Gemeinde,
nach langer Zeit mal wieder eine Frage.

Ich habe ein sehr komplexes Formular, in dem 400 Felder dargestellt werden, deren Daten aus einem entsprechenden Recordset mit exakt derselben Zeilen-Anzahl stammen. Die Daten aus dem Recordset werden im z.B. "on-Load-Event" aus einer Abfrage geladen, umgestaltet und in den passenden Feldern des Formulars dargestellt.

Meine Frage: Ich öffne das Recordset, um exakt 400 Datensätze zu erhalten und darzustellen. Wenn ich nun in irgendeinem der 400 Formularfelder Änderungen vornehme, möchte ich diese natürlich auch speichern. Dazu habe ich ein Array dirty(i) angelegt, das für jede geänderte "Zelle" des Formulars auf true gesetzt wird, wenn eben der Inhalt einer der 400 Formular-Elemente (via Popup-Formular) geändert wurde.

Beim Schließen des Formulars will ich das dirty-Array nun nach true absuchen und die passenden Records des Recordsets updaten.

Wie kann ich das am besten machen?

Natürlich brauche ich keine Antworten wie "Bitte Datenmodell überprüfen".

Es geht letztlich nur darum, ein Recordset komplett zu laden, an der Oberfläche mit etwas VBA kompakt darzustellen, ggf. einzelne Records zu ändern und zurück zu speichern, etwa so:

Recordset = Select * from Abfrage...
Formularfeld(i) = Mach-was-mit-dem-Record (optische Darstellung)
On Formularfeld(i).click
<Popup aufrufen>
Wenn Änderung: dirty(i) =true
Beim Schließen des Hauptformulars:
loop:
Wenn dirty(i): Record(i)=geänderte Daten
Abspeichern

Anders gesagt: Kann ich ein Recordset, das z.B. im on-load-event des Formulars geladen und dann irgendwie angezeigt wird in seiner Gänze als virtuelle Tabelle betrachten und Änderungen an einzelnen Datenzeilen dieser Tabelle relativ einfach verwalten? Wie kann ich auf einzelne "Zeilen" eines solchen Recordsets zugreifen?

Muss ich den Recordset beim Schließen des Formulars wieder abloopen, etwa so

recordset.movefirst
i=0
with recordset
i=i+1
if dirty(i) then
.feld1=Text1.value
.feld2=Blabla.value
...
.updatebatch
endif
.movenext
end with

.close

Noch anders gefragt: wie kann ich auf einzelne Records eines Recordsets lesend und schreibend zugreifen?

OK - komplizierte Frage, komplizierte Umgebung. Aber vielleicht hat jemand trotzdem eine zündende Idee.

Danke im Voraus für Antworten!

Gruß,

Dinkel

Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!
 

Offline Beaker s.a.

  • Access Guru
  • ****
  • Beiträge: 1686
Re: Recordset und Spezialformular
« Antwort #1 am: Januar 30, 2018, 16:00:34 »
Hallo,
Völlig unverständlich und sinnentleert.
Was haben den 400 Formfelder mit 400 DS zu tun?
Eine Abfrage hat Felder, deren Anzahl auf 255 gegrenzt ist.
Auf einem Formular ist jedes Feld aber nur einmal vorhanden, - kann
allerdings mehrfach angezeigt werden (Endlos bzw. Datenblatt).
Wenn die 400 jedoch alle ungebunden sind, würde ich dein RS nicht in
die Datenherkunft des Forms laden sondern im Klassenmodul als private
Property bereithalten. Ob das RS allerdings aktualisierbar ist musst du
selber herausbekommen, - ich vermute eher nicht.
gruss ekkehard
--
Beaker s.a., der lieber an seinem eigenen Projekt arbeiten würde/sollte, aber irgendwie immer gerne seinen Senf dazu gibt ;-)
S.M.I².L.E.
 

Offline PhilS

  • Administrator
  • Access-Profi
  • *****
  • Beiträge: 298
    • Tipps zu Access, VBA, SQL und Co.
Re: Recordset und Spezialformular
« Antwort #2 am: Januar 30, 2018, 18:59:49 »
Ich habe meine Zweifel, ob das mit dem Recordset so eine gute Idee ist.
Zum Laden der Daten natürlich, aber danach ist es vielleicht sinnvoller, die Daten in einem Array oder einer Collection im Speicher zu halten und dann mit benutzerdefiniertem Code (z.B. einzelnen Update-Statements) wieder zu speichern.

In einem Recordset kannst du über die AbsolutePosition-Property den Zeiger auf einen bestimmten Datensatz verschieben. Es müsste dann auch reichen, wenn du einmalig, vor dem Schließen des Recordsets das .UpdateBatch aufrufst.
 

Offline Wurliwurm

  • Access-Profi
  • **
  • Beiträge: 366
Re: Recordset und Spezialformular
« Antwort #3 am: Januar 31, 2018, 09:32:38 »
Anders gesagt: Kann ich ein Recordset, das z.B. im on-load-event des Formulars geladen und dann irgendwie angezeigt wird in seiner Gänze als virtuelle Tabelle betrachten und Änderungen an einzelnen Datenzeilen dieser Tabelle relativ einfach verwalten?

Ja.

Mach Dir das Leben nicht unnötig schwer und schieß nicht durch die Brust in´s Knie. Laß Dich auch nicht begriffsverwirren, so ein Recordset ist eine Collection und weit mächtiger als ein Array.

Die Bindung von einem an ein Endlosformular gebundenes Recordset ist bidirektional. Wenn in einer Zeile im Endlosformular der Eintrag per Tastatureingabe manipuliert wird, wird der aktuelle Wert auch in das Recordset übertragen. Vorausgesetzt, das RS ist updatebar. Ein Recordset, welcher mit einer SQL-Abfrage verknüpft ist, ist auch direkt mit der Datenbank verbunden. Damit gibt es ggfalls eine indirekte Bindung von den Datenbankfeldern an die Eingabefelder im Formular.
 

Offline crystal

  • Access-Profi
  • **
  • Beiträge: 382
Re: Recordset und Spezialformular
« Antwort #4 am: Januar 31, 2018, 18:56:58 »
Hallo,
zunächst einmal an "Beaker s.a.": Deine Antwort zeigt, dass du meine Frage nicht verstanden hast (Vermischung von Recordset, Record und Record-Feldern). Aussagen wie "sinnentleert" sollte man daher vorsichtig verwenden, um nicht in den Verdacht zu geraten, selbst als "sinnentleert" zu gelten. Immerhin sprichst du noch vage Vermutungen aus, die es zu recherchieren wert sind. Warum nicht gleich konkret?

Mir geht es nur um folgendes Formular (siehe Anlage).
Vielleicht kann mir jemand einen Tipp geben, wie ich dieses Formular mit seinen vielen ungebundenen Feldern besser hinkriegen kann, bin für jede Idee offen.

Gruß,
c
Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!
 

Offline PhilS

  • Administrator
  • Access-Profi
  • *****
  • Beiträge: 298
    • Tipps zu Access, VBA, SQL und Co.
Re: Recordset und Spezialformular
« Antwort #5 am: Januar 31, 2018, 19:50:18 »
Der Screenshot hätte die Situation gleich von vornherein klarer machen können.
Vielleicht kann mir jemand einen Tipp geben, wie ich dieses Formular mit seinen vielen ungebundenen Feldern besser hinkriegen kann, bin für jede Idee offen.
Meinen Hinweis bzgl. der Collection zur Verwaltung der Daten im Speicher würde ich auch mit diesen Zusatzinformationen aufrechterhalten.

Es wäre aber evtl. ebenfalls möglich, dieses Formular als gebundenes Endlosformular zu erstellen.
Wenn ich es richtig verstanden habe, sollen keine Daten direkt in dem Form geändert werden, sondern zur Dateneingabe gibt es davon ausgehend einen separaten Dialog. Dann könnte als Datenherkunft eine Kreuztabellenabfrage dienen.
Die farbliche Gestaltung wäre evtl. über bedingte Formatierungen lösbar. Allerdings gibt das bei so vielen Feldern u.U. einen unschönen Flacker-Effekt.
Ich erinnere mich auch dunkel an eine vergleichbare Lösung mit Grafiken zur optischen Gestaltung.

Wenn das Kalenderformular read-only wäre, dann könntest du die Änderung von Daten recht simpel über das Detail-Dialog-Form erledigen. - Das wäre vermutlich eine vergleichsweise einfache Lösung.



 

Online DF6GL

  • Global Moderator
  • Access-Oberguru
  • *****
  • Beiträge: 23216
Re: Recordset und Spezialformular
« Antwort #6 am: Januar 31, 2018, 20:32:29 »
Hallo,

m. E. wird mit diesem Formular nicht viel editiert...
 
Mit einer Kalendertabelle als Datenbasis, die im Vorfeld mit einer Insert-Abfrage mit Jahresdaten gefüllt und evtl. mit Endlosform bezgl. Feiertagen und Betriebsferien (Farbe) editiert wird,

tblBetriebskalender

BkID
Bk_Tag
Bk_Monat
Bk_Jahr
BK_WoTag
Bk_Woche
Bk_Farbe

kann das gezeigte (ungebundene) Form mit geschickter Benennung der "stehenden Rechtecke" die Beschriftung (Caption) dieser Bezeichnungsfelder mit einer simplen Recordsetschleife in einem Rutsch füllen.


Alle anderen Bezeichnungsfelder sind statisch und brauchen nur bei der Formularerstellung gefüllt werden.


Allenfalls benötigt der 29.2. bei einem Schaltjahr besondere Beachtung.


Offline crystal

  • Access-Profi
  • **
  • Beiträge: 382
Re: Recordset und Spezialformular
« Antwort #7 am: Februar 01, 2018, 20:12:36 »
Liebes Forum,
vielen Dank für die Antworten.

Tatsächlich ist es so, dass die "Rechtecke" meines Formulars nicht direkt geändert werden können. Beim Klick auf eines der Rechtecke erscheint ein Popup-Dialog, der die Daten des Rechtecks nochmal darstellt und an erlaubten Stellen Änderungen zulässt.

Momentan verwalte ich das alles in public Arrays. Die Frage ist nur, ob oder wie ich es irgendwie schaffen kann, die ursprüngliche Abfrage, also den begrenzten und "passenden" Recordset updatefähig zu gestalten. So wird in irgendeinem Rechteck z.B. nur ein "*" angezeigt. Im Popup sieht man dann z.B. "OstermoXtag". Diesen Schreibfehler korrigiere ich im Popup und möchte den korrigierten Wert natürlich zurück speichern.

Momentan mache ist das mit einem Dirty-Flag je Feld. Besser wäre es vom Gefühl her, die Änderung direkt in den Recordset zu schreiben und im Event "on Close" nur noch ein "UpdateBatch" ausführen zu müssen.

Vielleicht ist mein Ansatz grundlegend falsch, aber
1. ist er sehr übersichtlich (1 Jahr inkl. Vor- und Folgemonat auf einem Formular)
2. ist das Formular unmittelbar druckbar (passt auf DIN-A4)
3. werden Details über einen Popup-Dialog angesehen/geändert

Ich fürchte, ich komme nicht umhin, die Daten per Abfrage in eigene Arrays zu laden, ein pauschales "Dirty-Flag" pro Datums-Feld zu verwalten und dieses Dirty-Array dann beim Schließen des Formulars abzuarbeiten, um die Änderungen dann individuell zu speichern (mit eigenen ADO- bzw. DAO-Sequenzen).

Es gibt wohl keine Möglichkeit, ein solches Formular mit seinen vielen Feldern direkt an ein Recordset zu binden, oder???
(Wäre vielleicht ein Wunsch für zukünftige Access-Versionen...)

Oder würde sich vielleicht die Mühe lohnen, ein ähnliches Formular mit 427 bzw. 428 Unterformularen zu gestalten?

Momentan arbeite ich das Formular ungefähr so ab:
For i = 1 to 428
with me.controls("TD" & i)
<Schaltjahr prüfen>
.Value=<irgendwas>
.Backcolor=<Farbe>
...

Die betreffenden Felder haben Namen, die mit "TD" beginnen, also "TD1" bis "TD428", alle ungebunden. Ich verzichte sogar auf die Konvertierung von i in einen String, weil VBA das selbst macht und so kein führendes Blank entsteht ("TD1" statt ungewollt "TD 1").

Nun denn. Vielleicht hat jemand eine Idee, wie ich eine solche Darstellung sinnvoll, einfach und transparent mit einem Recordset verknüpfen kann. Inklusive Update einzelner "Zellen" via Popup.

Ich bin - wie gesagt - für jede Idee dankbar. Da ich aber kein Access-Profi bin, wäre ich an etwas konkreteren Aussagen, evtl. mit Code-Fragmenten, interessiert. Vielleicht gibt es auch ein Kalender-Steuerelement, das ich benutzen könnte.

Liebe Grüße,

c.
Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!
 

Online DF6GL

  • Global Moderator
  • Access-Oberguru
  • *****
  • Beiträge: 23216
Re: Recordset und Spezialformular
« Antwort #8 am: Februar 02, 2018, 08:59:44 »
Hallo,

das geht doch viel einfacher ...

in meinem letzten Post steht der Hinweis, die Felder "geschickt" zu benennen und nicht  einfach nur durch zu nummerieren.


z. B.:


ID021200    für den zweiten Dezember 2017   "00"  steht für das Vorjahr
oder
ID110301   für den elften März 2018  "01" steht für das im Kombi gewählte Jahr (2018)

usw.

In der vorgeschlagenen Recordset-Schleife

Sub SetCaption()
Dim DatVon as Date, DatBis as Date, rs as Dao.Recordset
DatVon = Dateserial (Me!Datum,0,1)
DatBis = Dateserial (Me!Datum,14,0)
.
.
.
set rs = Currentdb.Openrecordset ("Select * from tblBetriebskalender where Bk_Datum between " & _
Format(DatVon,"\#yyyy-mm-dd\#") & " and "  & Format(DatBis,"\#yyyy-mm-dd\#") & " order by Bk_Datum"
, dbOpenScnapshot

wird bei jedem Feld dessen Caption so gesetzt:

Me("ID" & rs!Bk_Tag & rs!Bk_Monat & Format(rs!Bk_Jahr-Me!cmbJahr+1).Caption = rs!Bk_WoTag

.
.
.
End Sub



Beim Klick auf ein (Tag-)Bezeichnungsfeld kann  der Tag und Monat "abgelesen" werden, dem dieses Feld zugeordnet ist und das ja auch  entspr o. st. Codefragmenten gesetzt wurde. Durch Übergabe des daraus resultierenden Datums an die Where-Condition der Openform-Methode öffnet sich das Editier-Formular mit dem passenden Datensatz.

Dim strDatum as String, ctlAkt as Control
ctlAkt = Screen.AktiveControl.Name
strDatum=  Format(Dateserial(Mid(ctlAkt,7),(Mid(ctlAkt,5,2),Mid(ctlAkt,2,2)+ Me!cmbJahr),"\#yyyy-mm-dd\#")

.
.

Docmd.Openform "frmBKEdit", , ,"Bk_Datum = " & strDatum , , acDialog

'Formular aktualisieren, indem die Recordset-Schleife erneut abgestoßen wird.

Alles Luftcode, den restlichen Code bekommst Du sicher selber zustande.


PS: in die Tabelle muss noch das Feld "Bk_Datum"  mit Datentyp Datum/Uhrzeit hinein.

Offline crystal

  • Access-Profi
  • **
  • Beiträge: 382
Re: Recordset und Spezialformular
« Antwort #9 am: Februar 02, 2018, 14:54:32 »
Lieber Franz,

vielen Dank für deine ausführlichen Gedanken!
Meine Implementierung sieht etwas anders aus. Ich lade das Recordset mit
folgender Sequenz:

        strDB = "SELECT TId, TBKalBox12, TBKalBox3, TFBez, TTyp, TAnzG, TAnzU, TAnzK FROM Tage " & _
                "WHERE (((Tage.TId) Between #12/1/" & intJahrD - 1 & "# And #1/31/" & intJahrD + 1 & "#)) " & _
                "ORDER BY Tage.TId;"
   
        Set rstDB = New ADODB.Recordset
   
        rstDB.ActiveConnection = CurrentProject.Connection
        rstDB.Open strDB, , adOpenStatic, adLockReadOnly

        arrDaten = rstDB.GetRows
       
        rstDB.Close
        Set rstDB = Nothing
       
        intTagIndex = 0
       
        For i = 0 To UBound(arrDaten, 2)
            intTagIndex = intTagIndex + 1
            datKal(intTagIndex) = arrDaten(0, i)
           
            strBKalX(intTagIndex) = Nz(arrDaten(1, i), "      ")
usw.

Das geht sehr schnell. Die Arrays (z.B. datkal() und strBKal() sind public, so dass ich später im Popup-Formular einfach darauf zugreifen kann, z.B.

Private Sub Form_Load()
    If Me.OpenArgs <> "" Then
        strTag = Me.OpenArgs         'Name des aufrufenden Kontrollelements, z.B. TD34
        intTag = Int(Mid(strTag, 3)) 'Index des Aufruf-Tags, also 34
    Else
        Exit Sub
    End If
   
    txtDatum.Value = datKal(intTag)            'Datum
    txtDatumLang.Value = datKal(intTag)        'Datum lang
    txtWoTag.Value = Left(strBKalX(intTag), 2) 'Wochentag
    txtKW = Mid(strBKalX(intTag), 4, 2)        'KW
    If Mid(strBKalX(intTag), 3, 1) = "*" Then  'Feiertag J/N
        cboFT.Value = "J"
usw.

strTag und intTag sind wieder public deklariert, weil ich diese Variablen auch an anderen Stellen brauche.

Ich lade also die Recordset-Daten in einzelne public-Arrays, um dann z.B. im Popup-Dialog einfach darauf zugreifen zu können, ohne viel Parameter übergeben zu müssen. Nur der Name des aufrufenden Feldes reicht aus, um den Index der Arrays zu haben.

In diesen Arrays sind sowohl lange (sprechende) Bezeichnungen der Tage, Feiertage usw. gespeichert (zur Darstellung im Popup), als auch die konzentrierte knappe Version für das Kalender-Formular.

Mag sein, dass diese Implementation etwas skurril ist, aber sie erfüllt (bisher) ihren Zweck und ich kann auf verschiedene Kalendarien (Betriebs-Kalender oder Mitarbeiter-Kalender mit Urlaubs- und Krankheitstagen zugreifen) und alles in einem Kalender-Formular darstellen. Im Popup habe ich zusätzlich die Möglichkeit, z.B. Urlaub von-bis einzutragen und unmittelbar im aufrufenden Kalender-Formular farblich darzustellen.

Bisher funktioniert mein Kalender-Formular mit den Popup-Formularen (verschieden je nach Kalendertyp) ganz gut. Einziges Problem und Grund für meine Frage war, dass ich das Lesen, Ändern und Speichern der zugrunde liegenden Daten selbst verwalten muss und da war meine Hoffnung, das vielleicht durch geschickte Programmierung vereinfachen zu können. Ich hatte sowas vor Jahren schon Mal mit einer Datenklasse und entsprechenden Methoden gebaut, aber leider den Sourcecode nicht mehr. Deshalb jetzt nur mein prozeduraler Ansatz.

Vielleicht ist das Thema doch etwas zu umfangreich für ein Forum.

Trotz allem würde mich natürlich interessieren, wie Profis so eine kalenderbasierte Applikation realisieren würden.

Gruß
c.
Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!
 

Offline Lachtaube

  • Access Guru
  • ****
  • Beiträge: 1066
Re: Recordset und Spezialformular
« Antwort #10 am: Februar 02, 2018, 15:39:41 »
Ich würde die Anordnung für einen Jahreskalender so ändern, dass ich mit einer guten handvoll Steuerelementen auskäme. Die Daten eines Monats lassen sich mit einer Pivot-Hilfstabelle mittels SQL in 4 bis 6 Wochendatensätzen in einer Abfrage ermitteln. Diese Abfrage, jeweils mit entsprechendem Parameter versorgt, kann dann 12 x in einem Unterformular wirken. Feiertage und sonstige Perioden kann man mittels bedingter Formatierung hervorheben.
Grüße von der (⌒▽⌒)
 

Offline crystal

  • Access-Profi
  • **
  • Beiträge: 382
Re: Recordset und Spezialformular
« Antwort #11 am: Februar 02, 2018, 16:46:26 »
Hallo Lachtaube,

das sieht wirklich sehr elegant aus. Könntest du evtl. etwas "Luftcode" schreiben und posten? Das wäre sicher auch für andere sehr hilfreich.

Danke im Voraus.

Gruß
c.
Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!
 

Offline Lachtaube

  • Access Guru
  • ****
  • Beiträge: 1066
Re: Recordset und Spezialformular
« Antwort #12 am: Februar 02, 2018, 18:19:10 »
Kann ich machen.

Ich verwende eine Tabelle dual (angelehnt an Oracle) mit nur einem Feld id als Autowert und Primärschlüssel und nur einem Datensatz. Erstellt mit diesem einmal auszuführenden Code:
Sub CreateDualTable()
   Dim strSql As String
   
   strSql = "CREATE TABLE dual (id COUNTER CONSTRAINT pkey PRIMARY KEY);"
   Debug.Print strSql
   
   CurrentProject.Connection.Execute strSql
   strSql = "INSERT INTO dual (id) VALUES (1);"
   Debug.Print strSql
   
   CurrentProject.Connection.Execute strSql

   strSql = "ALTER TABLE dual" & vbNewLine & _
            vbTab & "ADD CONSTRAINT [There can be only one value in table dual]" & vbNewLine & _
            vbTab & "CHECK (" & vbNewLine & _
            vbTab & vbTab & "(SELECT Count(*) FROM dual) = 1" & vbNewLine & _
            vbTab & vbTab & ");"
   Debug.Print strSql
   
   CurrentProject.Connection.Execute strSql
End Sub
Im weiteren verwende ich eine Tabelle t500 (t31 würde in diesem Fall auch ausreichen). Zum Erstellen habe ich zunächst eine Abfrage q10 angelegt.SELECT CLng( 0 ) AS id
FROM   dual
UNION ALL
SELECT 1
FROM   dual
UNION ALL
SELECT 2
FROM   dual
UNION ALL
SELECT 3
FROM   dual
UNION ALL
SELECT 4
FROM   dual
UNION ALL
SELECT 5
FROM   dual
UNION ALL
SELECT 6
FROM   dual
UNION ALL
SELECT 7
FROM   dual
UNION ALL
SELECT 8
FROM   dual
UNION ALL
SELECT 9
FROM   dual;
Mithilfe dieser Abfrage habe ich eine Tabellenerstellungsabfrage für die t500 erzeugt.SELECT q2.id * 100 + q1.id * 10 + q0.id AS id
INTO   t500
FROM   q10 AS q0,
       q10 AS q1,
       q10 AS q2
WHERE  q2.id < 5
ORDER  BY q2.id * 100 + q1.id * 10 + q0.id;
Anschließend habe ich das Feld id manuell zum Primärschlüssel erkoren.

Nun habe ich eine Tabelle period mit den Datumsfeldern from und to (ja, ich weiß - sind reservierte SQL-Schlüsselworte) und einem Integer-Feld entry_type_id angelegt. In entry_type_id könnte man dann Werte eintragen, die bei der bedingtem Formatierung berücksichtigt werden. Eine Lookup-Tabelle habe ich mir dazu erspart - dürfte aber sinnvoll sein. Zusätzlich habe ich noch from und to als Pflichtfeld (Eingabe erforderlich = Ja) festgelegt, sowie in der Tabelleneigenschaft Gültigkeitsregel [from]<=[to] verankert. Anschließend habe ich einige Testdatensätze mit Feiertagen und der entry_type_id = 2 und einen Datensatz für Betriebsferien 24.02.2018 - 03.03.2018, entry_type_id = 1 eingetragen.

Nun kommt der etwas komplexe Teil des Abfragens mir einem Parameter (hier als @date bezeichnet) als Datumswert, das ich zunächst schreitweise zeige und hinterher in einer Abfrage erneut aufführe.

Zuerst benötigen wir eine einfache Abfrage x, die aus dem Datumsparameter das Datum des Monatsersten als Datum (dy) und den Monat (mth) ausgibt.
SELECT DateSerial( Year( [@date] ), Month( [@date] ), 1 ) AS dy,
       Month( [@date] )                                   AS mth
FROM   dual;

Nun müssen alle Daten dieses einen Monats in einer Abfrage y1 und auch die Daten des selben Monats aus period in Abfrage y2 ermittelt werden, die dann mittels Left Join zu einer Abfrage y verknüpft werden, um die entry_type_id aus y2 in die Monatsdaten einfließen lassen zu.können. Für beide Abfragen wird die Pivot-Tabelle t500 verwendet, deren erster Wert bei 0 anfängt.
y1 sieht so aus:
SELECT x.dy + id AS dy,
       mth
FROM   ( SELECT Dateserial( Year( [@date] ), Month( [@date] ), 1 ) AS dy,
                Month( [@date] )                                   AS mth
         FROM   DUAL ) AS x,
       T500
WHERE  id < 31 AND
       Month( x.dy + id ) = mth;
Analog dazu die passenden Daten aus Tabelle period in y2, wo ich entry_type_id zu et_id eingekürzt habe:SELECT [from] + id   AS dyp,
       entry_type_id AS et_id
FROM   period,
       t500
WHERE  id <= [to] - [from];
Die darauf basierende Abfrage y ist so festgelegt:SELECT dy,
       mth,
       et_id
FROM   ( SELECT x.dy + id AS dy,
                mth
         FROM   ( SELECT DateSerial( Year( [@date] ), Month( [@date] ), 1 ) AS dy,
                         Month( [@date] )                                   AS mth
                  FROM   dual ) AS x,
                t500
         WHERE  id < 31 AND
                Month( x.dy + id ) = mth ) AS y1
       LEFT JOIN ( SELECT [from] + id AS dyp,
                          entry_type_id AS et_id
                   FROM   period,
                          t500
                   WHERE  id <= [to] - [from] ) AS y2
              ON y1.dy = y2.dyp;
Jetzt fließt noch etwas VBA-Code mit ein, um die KW nach ISO 8601 zu ermitteln. In einem allgemeinen VBA-Modul __DateSupport steht dann:
Option Explicit

Public Function CalendarWeek(ByVal CheckDate As Date) As Integer
   Dim w As Integer

   CheckDate = Fix(CheckDate)
   w = DatePart("ww", CheckDate, vbUseSystemDayOfWeek, vbUseSystem)
   If w = 53 Then   'extra-check needed only in the last week of a year
      If Weekday(CheckDate, vbUseSystemDayOfWeek) = Weekday(CheckDate, vbMonday) Then
         Select Case Weekday(CheckDate, vbMonday)
            Case 1: If CalendarWeek(CheckDate + 1) < w Then w = 1
            Case 7: If CalendarWeek(CheckDate - 1) < w Then w = 52
         End Select
      End If
   End If
   CalendarWeek = w
End Function
Hier nun die finale Abfrage z, die ich unter qselMonthCalWithEntryType gespeichert habe.SELECT wk                          AS KW,
       Max( IIf( dw = 2, dm ) )    AS Mo,
       Max( IIf( dw = 2, et_id ) ) AS Mo_et_id,
       Max( IIf( dw = 3, dm ) )    AS Di,
       Max( IIf( dw = 3, et_id ) ) AS Di_et_id,
       Max( IIf( dw = 4, dm ) )    AS Mi,
       Max( IIf( dw = 4, et_id ) ) AS Mi_et_id,
       Max( IIf( dw = 5, dm ) )    AS Do,
       Max( IIf( dw = 5, et_id ) ) AS Do_et_id,
       Max( IIf( dw = 6, dm ) )    AS Fr,
       Max( IIf( dw = 6, et_id ) ) AS Fr_et_id,
       Max( IIf( dw = 7, dm ) )    AS Sa,
       Max( IIf( dw = 7, et_id ) ) AS Sa_et_id,
       Max( IIf( dw = 1, dm ) )    AS So,
       Max( IIf( dw = 1, et_id ) ) AS So_et_id
FROM   ( SELECT CalendarWeek( dy ) AS wk,
                Day( dy )          AS dm,
                Weekday( dy )      AS dw,
                mth,
                et_id
         FROM   ( SELECT dy,
                         mth,
                         et_id
                  FROM   ( SELECT x.dy + id AS dy,
                                  mth
                           FROM   ( SELECT DateSerial( Year( [@date] ), Month( [@date] ), 1 ) AS dy,
                                           Month( [@date] )                                   AS mth
                                    FROM   dual ) AS x,
                                  t500
                           WHERE  id < 31 AND
                                  Month( x.dy + id ) = mth ) AS y1
                         LEFT JOIN ( SELECT [from] + id AS dyp,
                                            entry_type_id AS et_id
                                     FROM   period,
                                            t500
                                     WHERE  id <= [to] - [from] ) AS y2
                                ON y1.dy = y2.dyp ) AS y ) AS z
GROUP  BY wk, mth = 12 AND
          wk = 1, mth = 1 AND
          ( wk = 52  OR
            wk = 52 )
ORDER  BY mth = 12 AND
          wk = 1 DESC, mth = 1 AND
          ( wk = 52  OR
            wk = 52 ), wk;
Nun habe ich ein Endlosformular frmMonth auf Basis der Abfrage angelegt, in dem Steuerelemente für die KW und die Wochentage existieren. Die RecordSource habe ich gelöscht.

Danach habe ich dieses Formular 12 x in ein Hauptformular eingefügt und es jeweils in sfr01..12 getauft. Mit einem Textfeld-Steuerelement Jahr (nicht im Bildanhang vorhanden) im Kopfbereich, lässt sich das Prozedere dann steuern. Das Steuerelement enthält Year(Date()) als Standardwert, die Gültigkeitsregel Between 100 And 9999 und 0 als Format-Einstellung. Folgender Code wird im Klassenmodul des Hauptformulars verwendet:Option Compare Database
Option Explicit

Private Sub Form_Load()
   Call SetupCalendarForYear(Year(VBA.Date()))
End Sub

Private Sub SetupCalendarForYear(ByVal Year As Integer)
   Const QRY_NAME As String = "qselMonthCalWithEntryType"

   Dim qdf As DAO.QueryDef
   Dim rs As DAO.Recordset
   Dim i As Long

   On Error GoTo e
   Set qdf = CurrentDb.QueryDefs(QRY_NAME)
   For i = 1 To 12
      qdf.Parameters("@date") = DateSerial(Year, i, 1)
      Set Me("sfr" & Format$(i, "00")).Form.Recordset = qdf.OpenRecordset
   Next
e:
   If Err Then Err.Clear
End Sub


Private Sub Jahr_AfterUpdate()
   Call SetupCalendarForYear(Me.Jahr)
End Sub

Ich hoffe, nichts wesentliches unterschlagen zu haben.

Viel Spaß beim umsetzen.

PS: In den Optionen zur Datenbank sollte die Objektnamen-Autokorrektur abgestellt sein, damit keine Konflikte mit dem Namen Jahr entstehen - ansonsten einfach konfliktträchtige Namen umbenennen.

PPS: wenn statt t500 bzw t31 eine fortlaufende Datumstabelle eingesetzt wird, erhöht sich natürlich die Performance.
Grüße von der (⌒▽⌒)
 
Folgende Mitglieder bedankten sich: PhilS

Offline crystal

  • Access-Profi
  • **
  • Beiträge: 382
Re: Recordset und Spezialformular
« Antwort #13 am: Februar 02, 2018, 19:56:02 »
Hallo Lachtaube,
vielen Dank für deine große Mühe.
Aber das scheint mir doch eher etwas über das Ziel hinausgeschossen zu sein.
Wer arbeitet in Access schon mit Constraints oder weiß, was das bedeutet.

Deine Lösung scheint auf den ersten Blick ja gut durchdacht und funktionsfähig zu sein, jedoch für den einfachen Access-Anwender etwas zu komplex.
Ich kenne ähnliche Ansätze noch aus rdb-Tagen unter VAX-VMS, aber für meine simple Anforderung erscheint diese Variante wohl doch zu komplex und zu schwer zu pflegen.

Statt der langen Union-Abfrage könnte man ja auch einfach eine Hilfstabelle mit genau der gewünschten Record-Anzahl benutzen. Dabei ist mir nicht klar, wie du verschiedene Werte aus "dual" selektieren willst, wenn dort nur genau ein Record gespeichert sein kann. Vielleicht habe ich etwas übersehen.

Naja, jedenfalls hast du dich mit diesem Beitrag als SQL-Experte ausgewiesen, sofern ich das beurteilen kann. Ich erstelle solche Hilfstabellen übrigens einfach mit Excel und importiere sie dann...

Resultat nach meiner persönlichen Einschätzung: zu kompliziert und für den normalen Access-Anwender kaum nachvollziehbar. Zudem habe ich ehrlich gesagt nicht alle Schritte nachvollzogen, da mir allein das Lesen deiner Post ein paar Haare zu Berge steigen ließ.

In meiner Anwendung gibt es bereits eine Tabelle mit jedem Tag jeden Jahres von 2018 bis 2030, Erweiterung leicht möglich, und Einträgen wie Kalenderwoche, Wochentag etc. Diese Tabelle könnte man einfach gruppieren oder pivotisieren, um deine Oberfläche zu bedienen. Ich muss aber sagen, dass mir mein linearer Ansatz doch etwas einfacher zu durchschauen scheint. Statt mit deinen 12 Unterformularen (sollten eigentlich 14 sein) umzugehen, halte ich meine Idee mit einigen 427/428-Arrays (14 Monate), in denen die Daten gehalten werden, doch für einfacher. Eine Collection oder eine Klasse könnte das vielleicht noch etwas vereinfachen, aber es geht auch mit "parallelen" Arrays.

Aber - wie gesagt - vielen Dank für deinen Beitrag.

Gruß,
c.
Wer Fehler in meinen Antworten findet, darf sie behalten, muss sie aber kommentieren. ;-)
Dies ist keineswegs arrogant gemeint, sondern soll nur unterstreichen, dass meine Antworten - natürlich - nicht immer fehlerfrei sind und sein können.
Devise: bitte immer erst selbst probieren!
 

Online DF6GL

  • Global Moderator
  • Access-Oberguru
  • *****
  • Beiträge: 23216
Re: Recordset und Spezialformular
« Antwort #14 am: Februar 02, 2018, 22:33:19 »
Hallo,


@Crystal:

kannst Du mal die DB mit den relevanten Objekten hier hochladen?

Ehrlich gesagt, weiß ich nicht , wo das Problem liegt...