Schreiben von zu vielen Einträgen in einer Datenbank

Burned

Mitglied
Hallo zusammen,

ich habe folgendes Problem: Ich will eine feste Anzahl von Zeilen in einer SQLite DB ändern. Die Anzahl wird zufällig, anhand eines Prozentsatzes ausgewählt. Ich habe das Ganze soweit, dass alles funktioniert, außer dass die Anzahl an geschriebenen Werten in der Datenbank zu hoch ist. Hier zuerst der Code, danach gebe ich euch ein Beispiel.

"vonBis" ist dabei ein String, der mitgegeben wird, zum Beispiel: "66 AND 70".
"wahrM" bzw. "wahrW" ist die Wahrscheinlichkeit, mit der die einzelnen Zeilen auf 3 gesetzt werden sollen, bei der Altersklasse zwischen 66 und 70 sind das für Männer 5%, für Frauen 20%.
"count" gibt die Anzahl von Reihen mit bestimmten Eigenschaften als int zurück (s.u.).
"blankUpdate" updated die DB (s.u.).

Java:
public static void verwitwetStmt(String vonBis, int wahrM, int wahrW) {
        String select;
        String preparedStmt;
        Random r = new Random();
        int rnd;
        int countW = 0;
        int countM = 0;
        // Zählen aller Männer in einem bestimmten Alter.
        int anzahl = DBUpdater.count("Jahre", "Jahre BETWEEN " + vonBis + " AND Geschlecht IS 0");

        // Verteilen des "verwitwet" Zustand gemäß der Wahrscheinlichkeit in der jeweiligen Altersgruppe.
        for (int i = 0; i < anzahl; i++) {
            rnd = r.nextInt(100);
            if (rnd <= wahrM)
                countM++;
            }
        System.out.println(anzahl + ", " +countM);
      
        // Statement für die Veränderung in der DB
        select = "SELECT ID FROM individuen WHERE Jahre BETWEEN " + vonBis + " AND Familienstand IS NULL "
                + "AND Geschlecht IS 0 ORDER BY RANDOM() LIMIT " + Integer.toString(countM) + ";";
        preparedStmt = "UPDATE individuen SET Familienstand = ? WHERE ID = ?";

        DBUpdater.blankUpdate(select, preparedStmt, 3);
      
        anzahl = DBUpdater.count("Jahre", "Jahre BETWEEN " + vonBis + " AND Geschlecht IS 1");
      
        for (int i = 0; i < anzahl; i++) {
            rnd = r.nextInt(100);
            if (rnd <= wahrW)
                countW++;
            }
      
        System.out.println(wahrW);
      
        select = "SELECT ID FROM individuen WHERE Jahre BETWEEN " + vonBis + " AND Familienstand IS NULL "
                + "AND Geschlecht IS 1 ORDER BY RANDOM() LIMIT " + Integer.toString(countW) + ";";
        preparedStmt = "UPDATE individuen SET Familienstand = ? WHERE ID = ?";

        DBUpdater.blankUpdate(select, preparedStmt, 3);
    }

Hier die "count" Methode:
Java:
ublic static int count(String spalte, String whereStmt) {
        DBController dbc = DBController.getInstance();
        dbc.initDBConnection();
        int anzahl = 0;
        try {
            Statement stmt = DBController.connection.createStatement();
            String select = "SELECT COUNT(" + spalte + ") FROM individuen WHERE " + whereStmt + ";";
            ResultSet rs = stmt.executeQuery(select);

            select = rs.getString(1);
            anzahl = Integer.parseInt(select);
            rs.close();
            stmt.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }
        return anzahl;
    }

Und hier die "blankUpdate" Methode:
Java:
public static void blankUpdate(String selectQuery, String preparedStatement, int wert) {
        DBController dbc = DBController.getInstance();
        dbc.initDBConnection();
        try {
            Statement stmt = DBController.connection.createStatement();
            ResultSet rs = stmt.executeQuery(selectQuery);
            PreparedStatement ps = DBController.connection.prepareStatement(preparedStatement);

            while (rs.next()) {
                ps.setInt(1, wert);
                ps.setInt(2, rs.getInt(1));
                ps.addBatch();
            }
            DBController.connection.setAutoCommit(false);
            ps.executeBatch();
            DBController.connection.setAutoCommit(true);
            ps.close();
            stmt.close();
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

Als Beispiel:
Anzahl von männlichen Personen zwischen 66 und 70: 2105
Prozent, die davon geschrieben werden sollen: 5%
CountM nach der for-Schleife: 130
Nach ausführen des Codes liefert nachfolgende SELECT-Abfrage in der DB 935 Zeilen zurück.

Code:
SELECT Familienstand FROM individuen WHERE Familienstand IS 3 AND Geschlecht is 0 and Jahre between 66 and 70

Weiß jemand, woran die Differenz liegen könnte? Ist was an meinen DB-Anfragen falsch? Ich finde meinen Fehler einfach nicht..
 
Zuletzt bearbeitet:
Falls du den Unterschied bei count und dem Update-Statement meinst, dann ist das Absicht. Count soll mir alle Frauen bzw. Männer in einer bestimmten Altersklasse zurückgeben. Geupdated werden sollen aber nur die, bei denen der Familienstand noch nicht geschrieben wurde.
 
Ich verstehe deinen code nicht so richtig.

Du hast 2105 Personen die in dem Bereich liegen der geändert werden soll. Davon sollen 5% geändert werden. Diese dann aber zufällig. Wozu ist denn nun die Schleife die den mCount erzeugt? Du kannst die Anzahl zu ändernden Personen doch einfach durch Prozentrechnung ermitteln. Anzahl = (2105 * 5) / 100;

Dann kannst du den ganzen Update in einem query machen

Code:
UPDATE individuen SET Familienstand = 3 
WHERE ID in (SELECT ID FROM (SELECT ID FROM individuen WHERE Jahre BETWEEN "+ vonBis +" AND Familienstand IS NULL "
               +"AND Geschlecht IS 1 ORDER BY RANDOM() LIMIT "+Anzahl+") as individuenalias)";

Der doppelte Select muss sein, da mysql kein select auf die gleiche Tabelle erlaubt in die auch geupdated wird.

Gruß

Claus
 
Du hast 2105 Personen die in dem Bereich liegen der geändert werden soll. Davon sollen 5% geändert werden. Diese dann aber zufällig. Wozu ist denn nun die Schleife die den mCount erzeugt? Du kannst die Anzahl zu ändernden Personen doch einfach durch Prozentrechnung ermitteln. Anzahl = (2105 * 5) / 100;

Vermutlich soll für jeden Eintrag selbst die Wahrscheinlichkeit, dass er geändert werden soll, bei 5% liegen und nicht einfach 5% der Werte geändert werden. Es ist also prinzipiell auch denkbar, dass gar kein Eintrag geändert wird. Das ist schon sinnvoll so und näher an der Realität 🙂
 
Vermutlich soll für jeden Eintrag selbst die Wahrscheinlichkeit, dass er geändert werden soll, bei 5% liegen und nicht einfach 5% der Werte geändert werden.

Genau deswegen. Danke stq 😉

Der doppelte Select muss sein, da mysql kein select auf die gleiche Tabelle erlaubt in die auch geupdated wird.

Das wusste ich nicht. Vielen Dank! Meine Lösung sieht jetzt so aus:

Java:
public static void verwitwetU65() {
        verwitwetStmt("66 AND 70", 5, 20);
        verwitwetStmt("71 AND 75", 10, 33);
        verwitwetStmt("76 AND 80", 14, 54);
        verwitwetStmt("81 AND 85", 25, 62);
        verwitwetStmt("86 AND 100", 37, 78);
    }
   
    public static void verwitwetStmt(String vonBis, int wahrM, int wahrW) {
        String select;
        String preparedStmt;
        Random r = new Random();
        int rnd;
        int countW = 0;
        int countM = 0;
        // Zählen aller Frauen in einem bestimmten Alter.
        int anzahl = DBUpdater.count("Jahre", "Jahre BETWEEN " + vonBis + " AND Geschlecht IS 0");

        // Verteilen des "verwitwet" Zustand gemäß der Wahrscheinlichkeit in der jeweiligen Altersgruppe.
        for (int i = 0; i < anzahl; i++) {
            rnd = r.nextInt(100);
            if (rnd <= wahrM)
                countM++;
        }
        System.out.println(anzahl + ", " +countM);
       
        DBController dbc = DBController.getInstance();
        dbc.initDBConnection();
       
        select = "UPDATE individuen SET Familienstand = 3 "
                + "WHERE ID in (SELECT ID FROM (SELECT ID FROM individuen WHERE Jahre BETWEEN "
                + vonBis +" AND Familienstand IS NULL AND Geschlecht IS 0 ORDER BY RANDOM() "
                        + "LIMIT "+countM+") as individuenalias);";
        try {
            Statement stmt = DBController.connection.createStatement();
            DBController.connection.setAutoCommit(false);
            stmt.executeUpdate(select);
            DBController.connection.setAutoCommit(true);
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        anzahl = DBUpdater.count("Jahre", "Jahre BETWEEN " + vonBis + " AND Geschlecht IS 1");
        for (int i = 0; i < anzahl; i++) {
            rnd = r.nextInt(100);
            if (rnd <= wahrW)
                countW++;
        }
        System.out.println(anzahl + ", " +countW);
       
        dbc = DBController.getInstance();
        dbc.initDBConnection();
       
        select = "UPDATE individuen SET Familienstand = 3 "
                + "WHERE ID in (SELECT ID FROM (SELECT ID FROM individuen WHERE Jahre BETWEEN "
                + vonBis +" AND Familienstand IS NULL AND Geschlecht IS 1 ORDER BY RANDOM() "
                        + "LIMIT "+countW+") as individuenalias);";
        try {
            Statement stmt = DBController.connection.createStatement();
            DBController.connection.setAutoCommit(false);
            stmt.executeUpdate(select);
            DBController.connection.setAutoCommit(true);
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

Vielen Dank für die Hilfe nochmal! Manchmal habe ich das Gefühl, ohne das Forum wäre ich vollkommen verloren..
 

Zurück
Oben