# "Abfrageschleife" auf Datenbank anweden



## Casio (30. Mai 2016)

Ich hab eine Datenbank mit folgenden Spalten ich versuchs mal so allgemein wie möglich zu stellen damit evtl. andere auch was davon haben:

Revier,Täter,Ort,Delikt alles mit Strings als Datentyp

ich hab folgende 3 Reviere in der Datenbank: 1010, 2020, 3030

dabei unterscheiden sie sich darin, das Revier 1010 nur den Fall übernimmt falls es sich beim Täter um Hansi123 handelt, die Tat in DE(Deutschland) begangen wurde und es sich um Mord handelt Sprich in der DB stehen jeweils in den Spalten folgendes:
Täter:Hansi123
Ort: DE
Delikt:Mord
Revier:1010

dann haben wir ein zweites Revier was den Fall immer übernimmt solang es um Hansi123 geht und es ein Mord war, sprich dem Revier ist es egal wo die Tat begannen wurde also müsste das irgendwie so vermerkt werden in der DB oder kp wie ich das implementier:

Täter:Hansi123
Ort: *
Delikt:Mord
Revier:2020

* = "egal" also alle Länder der Welt

und nun das dritte Revier, das ist noch etwas Toleranter, denen ist nur wichtig das Hansi123 daran beteiligt war sprich so:

Täter:Hansi123
Ort: *
Delikt:*
Revier:3030


So ich will nun eine Abfrage machen zur DB in der ich in der Reihenfolge abfrage:

1. wird geschaut ob alles passt, wenn ja => Revier 1010 kümmert sch darum (wird im return ausgespuckt)
2. wird geschaut ob wenigstens Hansi123 und ob das Delikt ein Mord war, wenn ja Revier 2020
3. wird geschaut ob wenigstens Hansi123 daran beteiligt war, wenn ja Revier 3030
4. wenn nichts davon zutrifft irgend einen Error als return ausspucken...


mein Ansatz:


```
public String responsibleRevier(String taeter, String ort, String delikt) {
        Query q = em.createQuery("SELECT a.Revier FROM Polizeistation a WHERE a.taeter = :taeter AND a.ort = :ort AND a.delikt = :delikt );
        q.setParameter("taeter", taeter);
        q.setParameter("ort", ort);
        q.setParameter("delikt", delikt);

String revier = (String) q.getSingleResult();
return revier;
```


das hier klappt schön und gut, aber ja wie gesagt das ist nur einer der oben 4 genannten Schritte, ich häng genau hier fest, weil mir ne Idee fehlt wie ich das andere Implementieren soll, ich vermute mal ich muss das irgendwie mit einer If-Schleife machen, dort sagen falls q.getSingleResult() == null ist dann die zweite Abfrage, aber ich weiß nicht wie ich da quasi Implementieren muss in meine DB das es völlig egal ist für das eine Revier was für eine Tat da stattgefunden hat, oder mach ich es dann einfach so das ich in meinem Query nur zwei WHERE clauses hab wo ich eben dann nur zwei vergleiche aufstell und bei der dritten Abfrage eben nur ein WHERE hab und da nur taeter vergleich?

==> Problem ist doch wenn ich so darüber nachdenke wenn ich dann nur nach dem Täter und dem Delikt frage wird mir das doch am Ende wieder ne Liste auspucken weil dann beispielsweise bei der Zweiten Abfrage Revier 1010 als auch Revier 2020 auf die WHERE clauses passen oder? Hab ich grad einen Denkfehler?


liebe Grüße, Casio


----------



## stg (31. Mai 2016)

Ich vermute du packst dein Problem falsch an. 
Die Datenbank ist (primär) nur für die Datenhaltung zuständig, nicht für die Interpretation der Daten. 
Die Zuweisung vom richtigen Revier zu einem Fall ist ein logisches Problem, welches bereits _vor_ dem Schreiben in die Datenbank gelöst werden sollte.
Gegebenenfalls kann man so etwas auch _beim_ Schreiben lösen, aber dann hat man eher eine Datenbankspezifische Lösung mittels Triggern, PL/SQL o.Ä.
Ich will nicht partout sagen, dass so etwas mit SQL nicht möglich ist, aber für mich versuchst du wie gesagt das Problem zum falschen Zeitpunkt und an der falschen Stelle zu lösen.

Wie auch immer, dass was einem `IF` in SQL am ähnlichsten ist, ist das `CASE` statement ... aber den Weg würde ich an deiner Stelle gar nicht erst einschlagen.


----------



## Casio (31. Mai 2016)

und wie sollte ich, das vor dem Schreiben der Datenbank lösen?


----------



## Thallius (31. Mai 2016)

Mir ist nicht ganz klar was genau du Abfragen willst. Willst du wissen welche Fälle Für Revier 3030 überbleiben weil sie durch 2020 und 1010 nicht abgedeckt sind? Aber dann muss es ja bestimmte Parameter geben nach denen du abfragst. Wenn du nur nach Hansi abfragst, kannst du ja gar nicht wissen ob der Ort und oder das Delikt nicht auf ein weiteres Revier zutreffe?

Oder gibt es die Konstellation, dass es für ein Delikt keinen Bezirk gibt, oder für eine Ort? Für mich ist das ganze einfach noch zu unklar als das man da helfen könnte. Ich denke auch wie stg, dass du im ganzen Konzept einen Fehler hast, aber da wir das Konzept nicht verstehen ist es schweirig.

Gruß

Claus


----------



## Casio (31. Mai 2016)

Diese Unklarheiten kann ich gerne ausräumen, ich will eine Stufenweise "Einteilung" der Reviere vornehmen, sprich auf gut Deutsch, falls die erste Abfrage passt, also wenn Ort,Delikt und Täter passen, dann soll NUR Revier 1010 den Fall bekommen, wenn nicht soll geprüft werden ob Revier 2020 den Fall übernimmt, dies ist nur dann der Fall wenn es wenigstens beim Täter und beim Delikt um die Parameter da oben geht, falls dies auch nicht zutrifft soll geprüft werden ob Revier 3030 den Fall übernimmt und das tut es eben nur wenn Hansi123 der Täter war, sprich der Ort kann von mir aus Brasilien sein und das Delikt irgendwie Banküberfall oder sowas..... und wenn das ebenfalls nicht zutrifft weil der Täter eben Lisa321 heißt, würd ich quasi einen Error zurückgeben also nicht mehr die letzte Spalte ausspucken in der immer meine Reviere stehen sondern einfach irgendwie eine Fehlermeldung....


Ich hoffe das mein Konzept jetzt klar ist falls immer noch nicht bin ich auch bereit das Beispiel weiter auszuführen

Es geht also vordergründung einfach darum zu sehen welches Revier am besten auf den Fall passt, dabei soll eben diese Vorgehensweise wie oben von mir beschrieben angewendet werden in genau der Reihenfolge

Grüße Casio


----------



## AndiE (31. Mai 2016)

Hi,

ich versuche mich mal. Soweit ich verstanden habe hast du eine Tabelle Polizeistation(Revier,Täter,Ort,Delikt). Nun füllst du diese mit Daten wie (1010, Ives,F,Baguettediebstahl) oder(2020,Nero,I,Brandstiftung). Irgendwie geht das nicht so, da die Reviernummer doch bei Eingabe der Daten nicht bekannt ist. Ich sehe zwischen revier und Fall eine 1:n-verbinung, wobei Fall(Täter,Ort, Delikt) ist.


----------



## Thallius (31. Mai 2016)

Aber beim erstellen eines Deliktes weist du doch welches Revier dafür zuständig ist?


----------



## AndiE (31. Mai 2016)

Gut, ganz genau würde ich noch eine Fall-ID vergeben. Dann kann ich einen Fall(FallID,Täter,Ort,Delikt) eingeben und anhand dieser Einträge in Zuweisung(Revier,FallID) den Fall dem Revier zuweisen. Wie ich einen Fall(FallID,Täter,Ort,Delikt) anlege, wenn ich den Täter erst ermitteln will, ist das Geheimnis des TO.


----------



## Casio (31. Mai 2016)

AndiE hat gesagt.:


> Hi,
> 
> ich versuche mich mal. Soweit ich verstanden habe hast du eine Tabelle Polizeistation(Revier,Täter,Ort,Delikt). Nun füllst du diese mit Daten wie (1010, Ives,F,Baguettediebstahl) oder(2020,Nero,I,Brandstiftung). Irgendwie geht das nicht so, da die Reviernummer doch bei Eingabe der Daten nicht bekannt ist. Ich sehe zwischen revier und Fall eine 1:n-verbinung, wobei Fall(Täter,Ort, Delikt) ist.




ja aber es geht darum, das ich später mal über ein UI neue Einträge mach und eine Methode haben will die quasi vergleicht okay was davon trifft zu? Und daraufhin eben nach der von mir erstellen DB ein Revier aussucht, ich hoffe es ist nun klar worauf ich hinaus will

kann ich das evtl irgendwie über eine for-each schleife machen? Ich hab ja im Prinzip 4 Cases : 
1. Case: Revier 1010 ist zuständig
2. Case: Revier 2020 ist zuständig
3. Case: Revier 3030 ist zuständig
4. Case:  Kein Revier zuständig irgend eine Errorausgabe

also ich hab 3 Zeilen in meiner DB die ich nacheinander mit dem vergleiche was ich quasi über irgend ein UI (später mal) eingebe wir können ja hardcodiert erstmal das annehmen was ich weiter oben gepostet hatte, wir haben eine Methode die Parameter erwartet und ich gebe dieser dann z.B. dann gewisse Sachen mit und ruf diese Methode halt irgendwo auf so in der Art:


```
String aufruf;

aufruf.responsibleRevier(hansi123, F, kaefer_ueberfahren)
```


----------



## KaffeeFan (31. Mai 2016)

Wie wäre es wenn du das ganze mit einer Enumeration machst? 
Hoffe ich habe mich jetzt nicht verschrieben, aber z.B. sowas in der Art:


```
public enum EinRevier
  {
    R1("Mord", "DEU", 1),
    R2("Brandstiftung", "US", 2),
    R3("Diebstahl", "AUS", 3);

    private String tat;
    private String ort;
    private int Revier;

    EinRevier(String aTat, String aOrt, int aRevier)
    {
      tat = aTat;
      ort = aOrt;
      Revier = aRevier;
    }
   
    public EinRevier getRevier(String aTat, String aOrt)
    {
      for (EinRevier revier : EinRevier.values())
      {
        if (revier.tat.equals(aTat) && revier.ort.equals(aOrt))
        {
          return revier;
        }
      }
      return null; //oder irgendein Fehler
    }
  }
```


----------



## Casio (31. Mai 2016)

Das wär schön und gut, nur fehlt mir dazu jetzt wiederum, das Wissen wie ich meine Zeilen aus der Datenbank im Programm code jeweils irgendwie auf diese Enumerationen mappe


----------



## mrBrown (31. Mai 2016)

Casio hat gesagt.:


> Das wär schön und gut, nur fehlt mir dazu jetzt wiederum, das Wissen wie ich meine Zeilen aus der Datenbank im Programm code jeweils irgendwie auf diese Enumerationen mappe



#valueOf und #name 
Allerdings haben Enums den Nachteil, das die bereits zur Compilerzeit feststehen müssen.


Jedes Revier hat eine Methode, die prüft ob es dafür zuständig ist (zb Predicate), dann wir einfach nur der Reihe nach geprüft, ob es zuständig ist, und wenn ja, es gesetzt.
Wenn du dynamisch Reviere erstellen willst, musst du dir nur überlegen, wie du die Bedingungen passend speicherst.
In deinem Beispiel einfach Ort, Name, Tat pro Revier speichern, und das Revier kann dann mit den übergeben Daten prüfen, ob es zuständig ist. (Das Prüfen lässt sich natürlich auch in externe Klassen auslagern)


----------



## stg (1. Jun 2016)

Casio hat gesagt.:


> Das wär schön und gut, nur fehlt mir dazu jetzt wiederum, das Wissen wie ich meine Zeilen aus der Datenbank im Programm code jeweils irgendwie auf diese Enumerationen mappe



Du benutzt doch JPA?! Das wird alles automatisch für dich erledigt.
Siehe: @Enumerated
Du kannst hierfür aber auch eigene Converter schreiben, wenn die beiden Standard-Mappings unzureichend sind.
Siehe dazu: @Convert @Converter und AttributeConverter


----------



## Casio (1. Jun 2016)

ich mach hierzu besser ein neues Thema auf, falls jemand danach sucht kommt er schneller drauf


----------

