Hallo zusammen,
ich habe 2 Tabellen A und B. Tabelle A enthält Daten, die in meiner Access-Datenbank gespeichert werden. Tabelle B wird bei jedem Datenbankstart durch Abruf von Daten über eine API aus einer anderen Datenbank neu gefüllt. Tabelle A und B enthalten einen eindeutigen Schlüssel, der die Einträge der beiden Tabellen miteinander verknüpft. Ich möchte nun Daten bestimmter Felder in Tabelle A durch (aktuellere) Daten aus Tabelle B ersetzten lassen, aber nur dann, wenn das entsprechende Feld in Tabelle B nicht Null ist - also Inhalt hat. Damit soll erreicht werden, dass Daten in Tabelle A nicht durch Nullwerte in Tabelle B überschrieben werden.
Ich hatte dazu eine Aktualisierungsabfrage erstellt, von er ich ursprünglich dachte, dass sie funktioniert. Leider stellte sich eben heraus das dem nicht so ist. Die Logik der abfrage ist: Ersetze Feld x1 aus Tabelle A durch Feld x1 aus Tabelle B, wenn Feld x1 aus Tabelle B nicht Null ist.
Das nicht Null Kriterium hab ich nun für alle Parameter in die Aktualisierungsabfrage aufgenommen, weil ich dachte, dass das Kriterium sich spezifisch zu dem zugehörigen Parameter verhält. Dem ist leider nicht so. Eine Aktualisierung der Daten findet nur dann statt, wenn alle Parameter in der Abfrag nicht Null sind.
Wie kann ich mit einer Aktualisierungsabfrage meine Tabelle A mit Feldspezifischen kriterien aktualisieren?
Lässt sich das mit Bordmitteln umsetzten oder muss ich mit VBA über meine Felder Loopen und dann für jedes Feld separat eine Aktualisierungsabfrage ausführen.
Wäre für schnelle Hilfe dankbar!
VG
Anbei mal noch etwas exemplarischer SQL-Code:
UPDATE tbl_pegel INNER JOIN tbl_kiwisQuery ON tbl_pegel.station_uuid = tbl_kiwisQuery.station_uuid
SET tbl_pegel.station_no = [tbl_kiwisQuery].[station_no], tbl_pegel.POS_AT_WTO = [tbl_kiwisQuery].[POS_AT_WTO]
WHERE (((tbl_kiwisQuery.station_no)<>"") AND ((tbl_kiwisQuery.POS_AT_WTO)<>"") AND ((Len([tbl_pegel].[station_uuid]))=Int(36)));
Wenn tbl_kiwisQuery.station_no keinen Inhalt hat, wird die ganze Aktualisierungsabfrage für die uuid nicht ausgeführt. Allerdings möchte ich, dass zumindest das Feld POS_AT_WTO aktualisiert wird, auch wenn das andere Feld keinen Inhalt hat. Die Logik, warum das nicht funktioniert ist mir klar. Ich hoffe allerdings, dass es eine "einfache" SQL Lösung gibt, die ich noch nicht kenne. Wenns nichts hilft muss ich eben bisschen VBA coden.
Hallo,
Warum prüfst du auf einen Leerstring, wo du doch NULL erwartest?
Wenn da NULL ankommt ergibt dein Vergleich FALSE.
im Direktfenster
s = NULL
?s <> ""
Falsch
gruss ekkehard
Hallo ekkehard, danke für deine Antwort!
Du hast recht, ich prüfe auf einen leeren String, das ist so richtig. Die Frage ist nun, wie ich erreichen kann, dass Feld 1 geupdatet wird, weil es inhalt hat, Feld 2 aber nicht, weil leer.
Ich könnte das erreichen, indem ich für jedes Feld eine separate Aktualisierungsbfrage erstelle.
Weil ich aber ca 20 verschiedene Felder updaten muss, würde ich mir das gerne sparen.
Entweder ich bastel mit da ein VBA For loop und gehe damit jeden parameter durch oder das geht irgendwie anders besser.
Vg
Hallo,
Zitatich prüfe auf einen leeren String, das ist so richtig.
Bist Du sicher ?
Normalerweise enthält ein leers Feld in einer Accesstabelle keinen Leerstring sondern NULL.
Wie kommt da ein Leerstring rein ?
Zum Nebenkriegsschauplatz:
WHERE FeldX > ""... würde ich auch verwenden (etwas Kleineres als den Nullstring gibt es nicht, < sollte also entfallen, da <> auch indexschädlich ist).
Man prüft auf Inhalt, NULL-Inhalte entfallen automatisch (da ein Vergleich mit NULL nie True ergibt), es ist eine Indexnutzung möglich im Unterschied zur Prüfung auf IS
NOT NULL.
Datentypentsprechend müsste man bei Zahlen und Datumswerten mit 0 prüfen (wenn erwartete Zahlen größer 0 und Datumswerte größer 30.12.1899 sind).
Zur eigentlichen Frage:
ZitatIch könnte das erreichen, indem ich für jedes Feld eine separate Aktualisierungsbfrage erstelle.
Darauf könnte es hinauslaufen, da man zumindest jeweils ein Feld über alle Datensätze (um wie viele handelt es sich?) aktualisieren könnte, wobei man natürlich in einer Schleife das betroffene Feld in einer sonst konstanten Anweisung austauschen könnte.
Es könnte aber auch so über alle Felder funktionieren (entsprechend erweitern):
...
SET A.station_no = IIF(B.station_no IS NULL, A.station_no, B.station_no)
...... also Ersetzen mit sich selbst, wenn kein neuer Wert geliefert wird. Hier wird man den Test auf NULL unmittelbar nutzen.
Durch die bedingten Zuweisungen entfallen entsprechende Prüfungen auf leer im WHERE-Teil, damit auch das unlösbare Logikproblem bei mehreren Feldern.
Statt IIF könnte man auch Nz einsetzen, weil kürzer. Nz ist aber nicht so typensicher wie die IIF-Variante, und IIF ist unmittelbarer Bestandteil des SQL-Sprachumfangs, während Nz eine Accessfunktion ist und also aus einer anderen Sprachwelt eingebunden wird.
Tipp: Verwende Tabellenaliase (https://www.ms-office-forum.net/forum/showthread.php?t=298432), damit die Anweisung kürzer und übersichtlicher bleibt.
Hallo zusammen, kurze Rückmeldung. Das Problem ist gelöst.
Der Leerstring kommt durch das parsen der Daten aus der externen Datenbank zustande.
Diese kann ich nur über einen HTTP-Get-Request erreichen. Der Request wird in einem Modul vorgenommen und als Format bekomme ich eine csv zurück. Ein Loop geht dann über alle Zeilen der csv und führt mit den einzelnen Parametern/Spalten ein SQL-Insert aus und füllt somit eine Tabelle.
Unten der Code, der das bewerkstelligt. Kann man bestimmt auch besser und effizienter gestalten aber so funktionierts wenigstens erstmal.
reqURL = "http://xxx.xxx.xxx:1234?request=getStationList&request=getSiteList&site_no=800,400,500,600,700,200,300,301,101,102,103,104,105,106,107,108,109,110,111&returnfields=ca_sta,station_uuid,station_name,station_no,site_name,river_name,station_latitude,station_longitude,station_local_x,station_local_y,station_georefsystem&ca_sta_returnfields=station_status,station_gauge_datum,station_gauge_datum_unit,PEGELKLASSE,PEGELART,DATENART,KONTROLLTURNUS,PEGELGRUPPE,POS_AT_WTO,BODY_RESPONSIBLE,hydrounit_name&format=csv"
req.Open "GET", reqURL, False
req.send
If req.Status <> 200 Then
MsgBox req.Status & " - " & req.StatusText
Exit Sub
End If
response = req.responseText
LineArray() = Split(response, vbLf, -1, vbTextCompare)
LineArray() = LineArray()
ub = UBound(LineArray)
lb = LBound(LineArray)
ReDim Preserve DataArray(UBound(LineArray))
'Globaler Parametervektor um Felder automatisiert einzufärben
parameterName() = Split(LineArray(0), ";")
'Lösche alle Wiski-Daten aus Tabelle um neue einzuspielen
sql_delete = "DELETE * FROM tbl_kiwisQuery"
CurrentDb.Execute (sql_delete)
For y = 1 To UBound(LineArray)
DataArray(y) = Split(LineArray(y), ";")
station_uuid = DataArray(y)(0)
station_name = DataArray(y)(1)
station_no = DataArray(y)(2)
site_name = DataArray(y)(3)
river_name = DataArray(y)(4)
station_latitude = DataArray(y)(5)
station_longitude = DataArray(y)(6)
station_local_x = DataArray(y)(7)
station_local_y = DataArray(y)(8)
station_georefsystem = DataArray(y)(9)
station_status = DataArray(y)(10)
station_gauge_datum = DataArray(y)(11)
station_gauge_datum_unit = DataArray(y)(12)
PEGELKLASSE = DataArray(y)(13)
PEGELART = DataArray(y)(14)
DATENART = DataArray(y)(15)
Kontrollturnus = DataArray(y)(16)
PEGELGRUPPE = DataArray(y)(17)
POS_AT_WTO = DataArray(y)(18)
BODY_RESPONSIBLE = DataArray(y)(19)
hydrounit_name = DataArray(y)(20)
sql_insert = "INSERT INTO tbl_kiwisQuery (station_uuid, station_name, station_no, site_name, river_name, station_latitude, station_longitude, station_local_x, station_local_y,station_georefsystem, station_status, station_gauge_datum, station_gauge_datum_unit, PEGELKLASSE, PEGELART, DATENART, KONTROLLTURNUS, PEGELGRUPPE, POS_AT_WTO, BODY_RESPONSIBLE, hydrounit_name) VALUES('" & station_uuid & "', '" & station_name & "', '" & station_no & "', '" & site_name & "', '" & river_name & "', '" & station_latitude & "', '" & station_longitude & "', '" & station_local_x & "', '" & station_local_y & "', '" & station_georefsystem & "', '" & station_status & "', '" & station_gauge_datum & "', '" & station_gauge_datum_unit & "', '" & PEGELKLASSE & "', '" & PEGELART & "', '" & DATENART & "', '" & Kontrollturnus & "', '" & PEGELGRUPPE & "', '" & POS_AT_WTO & "', '" & BODY_RESPONSIBLE & "', '" & hydrounit_name & "');"
'sql_insert = "INSERT INTO tbl_kiwisQuery(station_uuid, station_no, station_name) VALUES (1,2,3), (1,2,3), (1,2,3);"
CurrentDb.Execute (sql_insert)
Next y
Das eigentliche Problem des Threads hab ich jetzt auch gelöst. Einerseits war das Kriterium, dass die uuid immer 16 Stellen haben musste nicht richtig und wurde somit entfernt. Andererseits muss ich über alle einzelnen Parameter loopen und schauen ob dieser nun Inhalt hat oder nicht und somit für jeden Parameter eine eigene Aktualisierungsabfrage machen.
Dazu habe ich die Parameter (csv-Spaltennamen) in einem Vektor (1D Array) gespeichert und loope nun über jedes element des Vektors. Da die Namen der zugehörigen Spalten in den Access-Tabellen gleich sind, konnte ich so einfach ein SQL-Update-String aus den Parametern zusammenstellen und ausführen.
For y = 1 To UBound(parameterName)
parameter = parameterName(y)
updateSQL = "UPDATE tbl_pegel INNER JOIN tbl_kiwisQuery ON tbl_pegel.station_uuid = tbl_kiwisQuery.station_uuid SET tbl_pegel." & parameter & " = [tbl_kiwisQuery].[" & parameter & "] WHERE (tbl_kiwisQuery." & parameter & "<>"""");"
Debug.Print updateSQL
CurrentDb.Execute (updateSQL)
Next y
Debug.Print "Tabellen update ausgeführt!"
Ich danke euch für eure Anregungen.
VG