# zwei Strings vergleichen



## chrism120 (20. Nov 2019)

Hallo ich habe ein funKtion insertdb  () gemacht und  die  funktioniert einwandfrei. Aber ich will diesmal bevor ich die Daten in die Datenbank einfüge , möchte ich  2 Strings vergleichen. ob die Daten schon existieren einfach weiter. könnt ihr bitte einen Blick darauf werfen und mir bescheid sagen was ich falsch gemacht habe?
Unter ist meine Code

```
if (ad.isReachable(timeout)) {
                 try
                          {
                          Statment stat=conn.createStatement();
                         Resultset resultat=stat.executeQuery("SELECT HostName from Adresse ");
                          while (resultat.next()) {
                          String HostName = resultat.getString(2);
                            String adresse = ad.getHostName();
                            count(a);
                         if (HostName.equals(adresse)) {
                                 System.out.println("OK count" + adresse);
                                break;
                                                     }
                             else {
                insertdb("INSERT INTO Adresse (Ip,HostName,ThreadNummer) VALUES (?,?,?)", s, ad.getHostName(), 2);
                        count(a);
                            }
                    }
                } catch (SQLException e)
               {
                                    e.printStackTrace();
                    }
    }
```
Danke Im Voraus für Ihre Antwort


----------



## kneitzel (20. Nov 2019)

Also statt da durch alle Daten durch zu gehen kann man doch einfach gezielt nach dem Datensatz schauen, also ein SELECT HostName from Adresse where HostName = ?.

Ansonsten scheint das getString(2) falsch zu sein, denn Du fragst ja nur den HostName ab und sonst nichts. Es kommt also nur eine Spalte zurück.

Und dann ist auch die Logik falsch: Du bekommst also mehrere Datensätze.
Nun prüfst Du im ersten Datensatz: Ist der HostName der gesuchte? Nein -> INSERT
Dann der zweite Datensatz; Ist der der Hostname der gesuchte? Nein -> INSERT
Der dritte Datensatz ist dann der richtig - fein - aber Du hast schon zwei mal ein INSERT gemacht ...


----------



## mihe7 (20. Nov 2019)

Man kann die Duplikatsprüfung auch gleich der DB überlassen, z. B. 

```
INSERT INTO Adresse(Ip, HostName, ThreadNummer) 
  SELECT ?, ?, ? FROM (SELECT 1) x
   WHERE NOT EXISTS (SELECT 1 FROM Adressen WHERE HostName=?);
```

Bei 

```
INSERT INTO Adresse(Ip, HostName, ThreadNummer) 
  SELECT ?, x.Hostname, ? FROM (SELECT ? as Hostname) x
   WHERE NOT EXISTS (SELECT 1 FROM Adressen WHERE HostName=x.Hostname);
```
bin ich mir nicht ganz sicher, könnte aber auch funktionieren. Dann bräuchte man den Hostnamen nur einmal anzugeben.


----------



## chrism120 (20. Nov 2019)

JustNobody hat gesagt.:


> Also statt da durch alle Daten durch zu gehen kann man doch einfach gezielt nach dem Datensatz schauen, also ein SELECT HostName from Adresse where HostName = ?.
> 
> Ansonsten scheint das getString(2) falsch zu sein, denn Du fragst ja nur den HostName ab und sonst nichts. Es kommt also nur eine Spalte zurück.
> 
> ...


ich verstehe nicht ganz genau was Du meinst. Kanst Du bitte es modeliren ?


----------



## chrism120 (20. Nov 2019)

mihe7 hat gesagt.:


> Man kann die Duplikatsprüfung auch gleich der DB überlassen, z. B.
> 
> ```
> INSERT INTO Adresse(Ip, HostName, ThreadNummer)
> ...


ich hatte es den Ansatz ausprobiert und habe kein gutes Resultat erhalten


----------



## mihe7 (20. Nov 2019)

chrism120 hat gesagt.:


> ich hatte es den Ansatz ausprobiert und habe kein gutes Resultat erhalten


Was heißt "kein gutes Resultat"? Hat es nicht funktioniert, war es langsam oder was war das Problem?


----------



## chrism120 (20. Nov 2019)

mihe7 hat gesagt.:


> Was heißt "kein gutes Resultat"? Hat es nicht funktioniert, war es langsam oder was war das Problem?


das hat einfach nicht funktioniert


----------



## mihe7 (20. Nov 2019)

Genauer, bitte. Ich gehe mal davon aus, dass Du meinen Tippfehler bei den Tabellennamen (Adressen statt Adresse) gesehen und korrigiert hast. Den Hostnamen musst Du in der ersten Variante für den 2. und 4. Parameter setzen, in der zweiten Variante wäre es dagegen nur der 3.


----------



## mihe7 (20. Nov 2019)

Hier mal ein Beispiel, mit MySQL getestet:

```
import java.sql.*;

public class Test {
    public static void main(String[] args) throws Exception {
        try(Connection conn = DriverManager.getConnection(args[0], args[1], args[2])) {
            createTable(conn);
            delete(conn, "127.0.0.1");
            insert(conn, "127.0.0.1", "localhost", Thread.currentThread().getId());
            insert(conn, "127.0.0.1", "localhost", Thread.currentThread().getId());        
        }
    }

    private static void createTable(Connection conn) {
        try(Statement stmt = conn.createStatement()) {
            stmt.execute("CREATE TABLE Adresse(ip varchar(20) not null primary key, " +
                         "HostName varchar(255) not null, " +
                         "ThreadNummer BIGINT not null);");         
        } catch (SQLException ex) {
            System.err.println("createTable: " + ex.getLocalizedMessage());
        }
    }

    private static void delete(Connection conn, String ip) throws Exception {
        try(PreparedStatement stmt = conn.prepareStatement(
                "DELETE FROM Adresse WHERE ip=?")) {
            stmt.setString(1, ip);
            int rowsDeleted = stmt.executeUpdate();
            System.out.printf("%d rows deleted.\n", rowsDeleted);
        }
    }

    private static void insert(Connection conn, String ip, String host, long thread) throws Exception {
        try(PreparedStatement stmt = conn.prepareStatement(
                "INSERT INTO Adresse(ip, HostName, ThreadNummer) " +
                "SELECT ?, ?, ? FROM (SELECT 1) x " +
                " WHERE NOT EXISTS (SELECT 1 FROM Adresse WHERE HostName = ?)")) {
            stmt.setString(1, ip);
            stmt.setString(2, host);
            stmt.setLong(3, thread);
            stmt.setString(4, host);

            int rowsInserted = stmt.executeUpdate();
            System.out.printf("%d rows inserted.\n", rowsInserted);
        }
    }
 
}
```

Bei einer Oracle DB müsstest Du "(SELECT 1) x" vermutlich durch "DUAL" ersetzen.

Auch die zweite Variante 

```
private static void insert(Connection conn, String ip, String host, long thread) throws Exception {
        try(PreparedStatement stmt = conn.prepareStatement(
                "INSERT INTO Adresse(ip, HostName, ThreadNummer) " +
                "SELECT ?, x.host, ? FROM (SELECT ? AS host) x " +
                " WHERE NOT EXISTS (SELECT 1 FROM Adresse WHERE HostName = x.host)")) {
            stmt.setString(1, ip);
            stmt.setLong(2, thread);
            stmt.setString(3, host);

            int rowsInserted = stmt.executeUpdate();
            System.out.printf("%d rows inserted.\n", rowsInserted);
        }
    }
```
funktioniert.


----------



## kneitzel (20. Nov 2019)

chrism120 hat gesagt.:


> ich verstehe nicht ganz genau was Du meinst. Kanst Du bitte es modeliren ?


Also ich hatte mehrere Punkte angesprochen. Bitte konkret sagen, was Du genauer haben willst.

Der erste Punkt war eine Lösung, bei dem Du entweder einen oder keinen Datensatz zurück bekommst. Die Abfrage muss dann halt wie folgt aussehen:
`SELECT HostName from Adresse where HostName = ?`
Aufzubauen wäre dann die Abfrage selbst über ein PreparedStament ähnlich wie bei Deinem INSERT. (Zumindest gehe ich davon aus, dass Du das dort verwendet hast.)

Der zweite Punkt ist ein Fehler beim Auslesen des ResultSets. getString(2) gibt den Wert aus der zweiten Spalte. Aber Du hast nur eine Spalte (HostName).

Der dritte Punkt, ist der Logik-Fehler: Wenn Du in einer Schleife ein if/else hast, dann wird für jeden Wert in der Schleife entweder der if Part oder der else Part ausgeführt. Also wenn die ersten x Datensätze in das else laufen, dann hast Du das x mal ausgeführt ....

Ansonsten gefällt mir die Lösung von mihe7 sehr gut. Hier wäre aber noch die Frage, welche Datenbank Du genau verwendest. Einige haben dafür auch spezielle Lösungen (mysql/mariadb z.B.), die eben nicht Standard SQL sind.


----------



## chrism120 (21. Nov 2019)

JustNobody hat gesagt.:


> Also ich hatte mehrere Punkte angesprochen. Bitte konkret sagen, was Du genauer haben willst.
> 
> Der erste Punkt war eine Lösung, bei dem Du entweder einen oder keinen Datensatz zurück bekommst. Die Abfrage muss dann halt wie folgt aussehen:
> `SELECT HostName from Adresse where HostName = ?`
> ...


Moin. ok Danke für deine Rückmeldung. ich verwende Mysql als Datenbank


----------



## chrism120 (21. Nov 2019)

mihe7 hat gesagt.:


> Hier mal ein Beispiel, mit MySQL getestet:
> 
> ```
> import java.sql.*;
> ...


Morgen!! Danke.


----------



## kneitzel (21. Nov 2019)

*Als erstes gefällt mit der Vorschlag von mihe7 sehr gut, denn der sollte so bei zumindest den meisten Datenbanken direkt funktionieren. Daher würde ich zu der Lösung raten!*

Ich hatte aber MySQL spezifische Möglichkeiten angesprochen (Evtl. aufpassen, dass Du eine aktuelle mysql Version hast!):

*INSERT IGNORE*. Setzt ein unique key auf HostName voraus (So da jeder HostName nur einmal vorkommen soll, so sollte der auf jeden Fall gesetzt sein!) Dokumentation dazu wäre z.B.: http://www.mysqltutorial.org/mysql-insert-ignore/
Unter dem Strich ist es wie ein normales INSERT nur eben durch das IGNORE wird ein Fehler beim Uniqe Key nicht als Fehler behandelt sondern ignoriert. (Und die Datenbank dürfte da auch etwas optimieren hoffe ich...)

Interessant sind dann aber auch die Konstrukte (die Du aber hier nicht brauchst, da Du nur ein Insert machen willst und kein Update):
*INSERT INTO ..... ON DUPLICATE KEY UPDATE .... ; **http://www.mysqltutorial.org/mysql-insert-or-update-on-duplicate-key-update/*
==> Dies ist ein zusammengefasstes INSERT und UPDATE statement. Da muss man dann nicht erst prüfen und dann entweder oder machen sondern hat einen kompakten Befehl.

*REPLACE INTO ...* http://www.mysqltutorial.org/mysql-replace.aspx
Dies ist prinzipiell ähnlich wie der INSERT ...ON DUPLICATE KEY ...

Ich selbst kenne diese Konstrukte, aber ich selbst vermeide diese so gut es geht, da es zusätzliche Abhängigkeiten schafft und eine Portierung erschwert.


----------



## chrism120 (22. Nov 2019)

JustNobody hat gesagt.:


> *Als erstes gefällt mit der Vorschlag von mihe7 sehr gut, denn der sollte so bei zumindest den meisten Datenbanken direkt funktionieren. Daher würde ich zu der Lösung raten!*
> 
> Ich hatte aber MySQL spezifische Möglichkeiten angesprochen (Evtl. aufpassen, dass Du eine aktuelle mysql Version hast!):
> 
> ...


Danke


----------

