Access-o-Mania

Access-Forum (Deutsch/German) => Access Programmierung => Thema gestartet von: Adrjan am April 01, 2016, 16:40:30

Titel: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 16:40:30
Hallo zusammen,

gibt es irgendeine Möglichkeit, dieses Statement funktionstüchtig zu bekommen?

Me!Liste.RowSource = "SELECT * , (33959 * acos( cos( radians('" & Me.Breitengrad & "') ) * cos( radians(Geo.latitude) )* cos( radians(Geo.longitude ) - radians('" & Me.Laengengrad & "') ) + sin(radians('" & Me.Breitengrad & "') ) * sin( radians(Geo.latitude) ))) AS distanz  " & _
"FROM Geo " & _
"HAVING distanz < 20 "

Ziel ist es, in meinem Listenfeld, nur die Datensätze aus der Tabelle "Geo" abzubilden, welcher innerhalb des 20km Umkreises vom Breitengrad aus "Me.Breitengrad " und dem Längengrad aus "Me.Laengengrad " liegen.

Ich bin leider nicht wirklich fit in sachen VBA und allgemein auch Access.
Bisher sind leider alle meine Lösungsansätze gescheitert.
Scheinbar kann Access nicht mit den Funktionen "acos" und "radians" umgehen.

Habt ihr eine Idee wie ich das hinbekommen kann?

Vielen lieben Dank bereits für Eure Hilfe.

Viele Grüße
Adrjan
Titel: Re: Umkreissuche Access SQL
Beitrag von: MzKlMu am April 01, 2016, 17:37:34
Hallo,
versuche das mal so:

Me!Liste.RowSource = "SELECT * FROM Geo WHERE  (33959 * acos( cos( radians('" & Me.Breitengrad & "') ) * cos( radians(Geo.latitude) )* cos( radians(Geo.longitude ) - radians('" & Me.Laengengrad & "') ) + sin(radians('" & Me.Breitengrad & "') ) * sin( radians(Geo.latitude) ))) < 20"

Zeilenumbrüche musst Du einfügen, war ich jetzt zu faul dazu.

Das berechnet Feld wird nicht benötigt. Wenn Du es sehen willst, musst Du das mit der gleichen Formel eintragen. Die Formel wird also für das Feld benötigt und die WHERE Klausel.
Titel: Re: Umkreissuche Access SQL
Beitrag von: DF6GL am April 01, 2016, 17:57:04
Hallo,

die Radians-Funktion gibt es in Access-VBA/SQL nicht...

Möglicherweise geht dieses:


Dim strSQL as String
strSQL =SELECT * , fktDist( " & str(Me!Breitengrad) & ", latitude , longitude, " & str(Me!Laengengrad) & ") AS distanz  FROM Geo HAVING distanz < 20

Me!Liste.RowSource = strSQL



und in einem Standard-Modul

ZitatPublic Function fktDist(Breitengrad As Double, latitude As Double, longitude As Double, Laengengrad As Double)
fktDist = 33959 * acos(Cos(Atn(Breitengrad)) * Cos(Atn(latitude)) * Cos(Atn(longitude) - Atn(Laengengrad)) + Sin(Atn(Breitengrad)) * Sin(Atn(latitude)))
End Function
Titel: Re: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 18:33:18
Vielen Dank für eure Antworten.
Leider scheint es noch nicht zu funktionieren.

Dim strSQL as String
strSQL = "SELECT * , fktDist( " & str(Me!Breitengrad) & ", latitude , longitude, " & str(Me!Laengengrad) & ") AS distanz  FROM Geo HAVING distanz < 20"
Me!Liste.RowSource = strSQL

Public Function fktDist(Breitengrad As Double, latitude As Double, longitude As Double, Laengengrad As Double)
fktDist = 33959 * acos(Cos(Atn(Breitengrad)) * Cos(Atn(latitude)) * Cos(Atn(longitude) - Atn(Laengengrad)) + Sin(Atn(Breitengrad)) * Sin(Atn(latitude)))
End Function

Leider erscheint nur eine leere Tabelle im Listenfeld.
Ein Fehler wird allerdings nicht angezeigt, nur finde ich nicht, woran es noch liegen kann.

Viele Grüße

Titel: Re: Umkreissuche Access SQL
Beitrag von: MaggieMay am April 01, 2016, 18:40:51
Hallo,

ersetze mal HAVING durch WHERE.
Titel: Re: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 18:45:54
Zitatersetze mal HAVING durch WHERE.
Leider hatte das keine Auswirkung.
Titel: Re: Umkreissuche Access SQL
Beitrag von: MaggieMay am April 01, 2016, 18:55:03
Dann nimm den generierten SQL-Code und teste ihn im SQL-Fenster einer neuen Abfrage.

PS:
Sorry, aber der Ansatz von Klaus war schon ganz richtig, du kannst das berechnete Feld nicht im Kriterium verwenden.
Da muss also der komplette Ausdruck noch einmal ausgeschrieben werden.
strSQL = "SELECT * , fktDist( " & str(Me!Breitengrad) & ", latitude , longitude, " & str(Me!Laengengrad) & ") AS distanz  " & _
            "FROM Geo WHERE fktDist( " & str(Me!Breitengrad) & ", latitude , longitude, " & str(Me!Laengengrad) & ")< 20"
Titel: Re: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 19:00:15
In einer gesonderten Abfrage kann ich die Public function aber nicht ansteuern (Undefinierte Funktion).

Public Function fktDist(Breitengrad As Double, latitude As Double, longitude As Double, Laengengrad As Double)
fktDist = 33959 * acos(Cos(Atn(Breitengrad)) * Cos(Atn(latitude)) * Cos(Atn(longitude) - Atn(Laengengrad)) + Sin(Atn(Breitengrad)) * Sin(Atn(latitude)))
End Function

ZitatDa muss also der komplette Ausdruck noch einmal ausgeschrieben werden.

Wie meinst du das genau?
Titel: Re: Umkreissuche Access SQL
Beitrag von: MaggieMay am April 01, 2016, 19:01:59
Code siehe oben.

Befindet sich die Funktion nicht in einem allgemeinen Modul?
Titel: Re: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 19:28:38
Ah OK.
Ich habe die Funktion nun in ein eigenes (allgemeines) Modul eingetragen. Jetzt greift die Abfrage darauf zu.

Also wenn ich das HAVING durch WHERE ersetze, dann kann er den Parameter "distanz" nicht finden.
Wenn ich "HAVING" belasse, dann erhalte ich die Fehlermeldung "HAVING-Klausel (distanz<20) ohne Gruppierung oder Aggregatfunktion".


Titel: Re: Umkreissuche Access SQL
Beitrag von: MzKlMu am April 01, 2016, 19:30:50
Hallo,
wie soll man einen Vorschlag machen, wenn man nix sieht ?

Zeige daher bitte den vollständigen aktuell verwendeten SQL_Code.
Titel: Re: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 19:33:35
Sorry.
Ich teste gerade folgende Abfrage:

SELECT *, fktDist(33.3334,Geo.latitude,Geo.longitude,69.952) AS distanz
FROM Geo
WHERE distanz < 20;
Titel: Re: Umkreissuche Access SQL
Beitrag von: MzKlMu am April 01, 2016, 19:36:21
Hallo,
wie ich weiter oben schon geschrieben habe, muss in der Wherklausel die Berechnung auch verwendet werden.

SELECT *, fktDist(33.3334,Geo.latitude,Geo.longitude,69.952) AS distanz
FROM Geo
WHERE fktDist(33.3334,Geo.latitude,Geo.longitude,69.952) < 20


Brauchst Du das Feld Distanz zur Anzeige ?
Titel: Re: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 19:44:00
Ja, ich möchte das Feld Distanz mit in das Listenfeld aufnehmen.
Die Abfrage funktioniert mit deinem Code zwar fehlerfrei, nur wird scheinbar kein Umkreis gefiltert, da alle Datensätze der Tabelle Geo angezeigt werden.

Bei der Public Function...

Public Function fktDist(Breitengrad As Double, latitude As Double, longitude As Double, Laengengrad As Double)
fktDist = 33959 * acos(Cos(Atn(Breitengrad)) * Cos(Atn(latitude)) * Cos(Atn(longitude) - Atn(Laengengrad)) + Sin(Atn(Breitengrad)) * Sin(Atn(latitude)))
End Function


..-musste ich noch eine weitere Funktion "ACos" hinzufügen, da Access anscheinend mit acos auch nicht umgehen kann.

Public Function ACos(x As Double) As Double
Const Pi = 3.14159265358979
'Pi = 4*Atn(1)
If x = 1 Then
  ArcCos = 0
ElseIf x = -1 Then
  ArcCos = Pi
ElseIf x < 1 And x > -1 Then
  ArcCos = Atn(-x / Sqr((-x * x) + 1)) + Pi / 2
End If
End Function


Wie gesagt, haut die Umkreissuche aber trotzdem nicht hin...
Titel: Re: Umkreissuche Access SQL
Beitrag von: MzKlMu am April 01, 2016, 19:59:41
Hallo,
was wird dann im Feld Distanz angezeigt, stehen da korrekte Zahlen ?

Du musst natürlich sicher sein, dass die Rechnung selbst stimmt. Zur Formel kann ich aber nichts sagen, habe ich keine Erfahrung.
Titel: Re: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 20:00:50
Nein im Feld Distanz werden nur "0"en angezeigt.
Wahrscheinlich stimmt hier tatsächlich etwas mit der Formel nicht.
Titel: Re: Umkreissuche Access SQL
Beitrag von: MzKlMu am April 01, 2016, 20:02:17
Hallo,
dann solltest Du natürlich erst mal sicher sein, dass die Formel korrekte Werte ermittelt. Erst dann kannst Du mal über das Filtern nachdenken.
Titel: Re: Umkreissuche Access SQL
Beitrag von: Adrjan am April 01, 2016, 20:07:09
Ich schaue mir morgen nochmal die Formel an.
Das liegt garantiert an der fktDist-Funktion.

Vielen Dank Dir und auch den anderen für Deine (Eure) Hilfe.
Das hat mir schon enorm weitergeholfen. :-)

LG & noch einen schönen Abend
Titel: Re: Umkreissuche Access SQL
Beitrag von: Beaker s.a. am April 01, 2016, 21:22:36
Hallo Ardjan,
Zitatdann solltest Du natürlich erst mal sicher sein, dass die Formel korrekte Werte ermittelt. Erst dann kannst Du mal über das Filtern nachdenken.
Und besonders hilfreich ist dabei die Methode .Print des Debug-Objekts (siehe OH).
gruss ekkehard
Titel: Re: Umkreissuche Access SQL
Beitrag von: bahasu am April 01, 2016, 22:35:55
Hallo,

im Rahmen einer Geocache-Datenbank hatte ich die folgenden Zeilen eingesetzt.
Vielleicht helfen die.

Harald

Option Compare Database
Option Explicit

    Const PI = 3.14159265


Public Function Entfernung(ByVal Breite_1, ByVal Laenge_1, ByVal Breite_2, ByVal Laenge_2 As String) As Double
    Const ErdUmfang = 6378
    Const Polarradius = 6357
    Const Exzentrizitaet = 0.081082     'Exzentrizität sqrt(1 - b^2/a^2)    a:Erdumfang, b:Polarradius

    Dim Breite_A, Breite_B, Laenge_A, Laenge_B As Double    'Koordinaten für zwei Punkte
    Dim Distanz As Double
    Dim ErdRadius  As Double
   

    Breite_A = Umwandeln(Breite_1)
    Laenge_A = Umwandeln(Laenge_1)
   
    Breite_B = Umwandeln(Breite_2)
    Laenge_B = Umwandeln(Laenge_2)
   
    ErdRadius = ErdUmfang * (1 - Exzentrizitaet ^ 2) / (1 - Exzentrizitaet ^ 2 * (Sin(Breite_A - (Breite_A - Breite_B) / 2)) ^ 2) ^ (3 / 2)

    'http://www.kompf.de/gps/distcalc.html
    Entfernung = ErdRadius * ArcCos(Sin(Breite_A) * Sin(Breite_B) + Cos(Breite_A) * Cos(Breite_B) * Cos(Laenge_B - Laenge_A))
End Function


Public Function Umwandeln(ByVal Eingabe As String) As Double
    Dim I As Byte
    Dim X As String
    Dim Nachkomma As Double
   
    Eingabe = Replace(Eingabe, "N", "")
    Eingabe = Replace(Eingabe, "E", "")
    Eingabe = LTrim(Eingabe)
   
    X = ""
    I = 1
    Do While IsNumeric(Mid(Eingabe, I, 1))
        X = X & Mid(Eingabe, I, 1)
        I = I + 1
    Loop

    Umwandeln = (Val(X) + Val(Mid(Eingabe, I + 1)) / 60) * PI / 180
End Function


Private Function ArcCos(X As Double) As Double
    'Arkuskosinus(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)
    'ArcCos = Atn(-x / Sqr(-x * x + 1)) + 2 * Atn(1)


    'http://dbwiki.net/wiki/VBA_Tipp:_Arcussinus_und_Arcuscosinus
    If X = 1 Then
        ArcCos = 0
    Else
        If X = -1 Then
            ArcCos = PI
        Else
            If X < 1 And X > -1 Then
                ArcCos = Atn(-X / Sqr((-X * X) + 1)) + PI / 2
            End If
        End If
    End If
End Function


Private Function ArcSin(X As Double) As Double
    'Arkussinus(X) = Atn(X / Sqr(-X * X + 1))
    ArcSin = Atn(X / Sqr(-X * X + 1))
End Function