SQL / select: group by Klausel


#1

Es gibt ja die GROUP BY-Klausel, wie kann ich jetzt “nur die besten 10 jeder Gruppe und die anderen nicht” auswählen?
quasi: Gruppen bilden, jede Gruppe sortieren, aus jeder Gruppe die besten 10 kopieren.


#2

sql - Using LIMIT within GROUP BY to get N results per group? - Stack Overflow
mysql - Get top n records for each group of grouped results - Stack Overflow


#3

Danke, leider komplizierter als gedacht…,

zB hab ich so etwas:
CREATE VIEW IF NOT EXISTS ALLE2 AS SELECT *, ROUND((SIZE * SN) / 100) AS FAK FROM SP GROUP BY DATUM ORDER BY FAK DESC;

wäre ja gut, wenn dann die Ergebnisliste nicht so lang ist.

Außerdem hab ich leider viele Zugriffe festgestellt, ich benutze serverless, kann ich irgendwie erst komplett im RAM arbeiten und hinterher auf die Festplatte schreiben?


#4

[QUOTE=CyborgBeta;122301]Außerdem hab ich leider viele Zugriffe festgestellt, ich benutze serverless, kann ich irgendwie erst komplett im RAM arbeiten und hinterher auf die Festplatte schreiben?[/QUOTE]
ACID steht dir leider da im Weg. Wenn du alles hinterher auf die Festplatte schreibst, kann ACID nicht gewährleistet werden.


#5

Spassig, wo sich doch deine Frage auf einen Lesenvorgang bezieht. Was willst du bei Lesezugriffen auf die Festplatte schreiben???


#6

Hallo Leute,

ja, meine Frage bezog sich auf eine View. Mittlerweile hab ich eine View auf einer View… Aber darum ging’s nicht.

Sqlite arbeitet serverless, ACID usw., was aber zur folge hat, das spätestens nach einem .close auf die Platte geschrieben werden muss.

Schlecht, denn ich hab hab ungefähr 600 Rows, die eingetragen werden. Mit :memory: (Sqlite arbeitet im RAM) brauche ich dafür 2 Sekunden und ohne, sehr viele Zugriffe auf die Platte und ca. 40 Sekunden, das ist ein riesiger Unterschied - dafür nicht temporär, transient usw.

Das ist noch nicht das gelbe vom Ei.


#7

Exakt, denn auch eine View hat erst mal gar nichts, überhaupt nichts, niente nada null mit Schreibvorgängen zu tun.


#8

Tipp zur RAM-Nutzung: Öffne deine Sqlite-Datei, erstelle einen Dump von ihr und importiere ihn in die Datenbank :memory:. Später könntest den Memory SQL-Dump nehmen und in einer neuen DB auf dem Dateisystem importieren.


#9

Danke für deinen Beitrag!

Könntest du mit jdbc driver in Java ein SSCCE mir zeigen, wie ich in eine geöffnete :memory: eine Datenbank file importieren und sie nach den ganzen Änderungen wieder zurückschreiben könnte?

Sqlite3.exe mit 2 MB ist ein riesiger Unterschied zu MySql mit locker 500 mb im RAM.

Edit:

So schaut das bei mir aus:

        conn = DriverManager.getConnection("jdbc:sqlite:test.sqlite");
        //conn = DriverManager.getConnection("jdbc:sqlite::memory:");
        createTable();
        createRows();
        deleteDoppelte();
        createViews();
        conn.close();```

Edit 2: BG, ich verstehe, was du meinst, aber wenigste mit Lesevorgängen könnten Views etwas tun habn, und das sind auch Festplattenzugriffe. ;)

#10

Deaktiviere das Performance-Schema ([inline]performance_schema = off[/inline] in der my.ini / my.cnf) und du bist bei etwa 20 MB RAM-Verbrauch.


#11

Tut mir leid, aber ich kenn mich JDBC nicht aus. Daher habe ich etwas mit dem ProcessBuilder gebastelt, um den Dump zu bekommen:

import java.io.OutputStreamWriter;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;

public class SqliteDump {
  public static void main(String[] args) throws IOException {
    Process process = new ProcessBuilder("sqlite3", "zum-dumpen.db").start();
    OutputStreamWriter osw = new OutputStreamWriter(process.getOutputStream());
    osw.write(".dump
"); // Schicke dem sqlite3-Binary den Befehl .dump
    osw.close();
    InputStream is = process.getInputStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte buf[] = new byte[4096];

    int n;
    while ((n = is.read(buf, 0, buf.length)) != -1) {
      baos.write(buf, 0, n);
    }
    is.close();
    System.out.println(baos.toString());
  }
}```

An sich sollte es kein Problem sein, die SQL-Befehle vom Dump in der :memory: Datenbank auszuführen. Andersrum müsstest du die Befehle, die du in der :memory: Datenbank ausgeführt hast, dann auch auf die Datenbank auf dem Dateisystem ausführen.

#12

Bitte schaue dir mal an:

https://docs.oracle.com/javase/6/docs/api/java/sql/Connection.html

java - Why set Autocommit to true? - Stack Overflow

liegt es an Autocommit?

Ansonsten, wie kann ich etwas direkt an sqlite3 schicken, nicht über ProcessBuilder, über createStatement?

commit, Rollback, Transaction, BOT — Brauche ich ja gar nicht. Wenn etwas “schiefgeht”, starte ich nochmal und ein normaler Zustand wird wiederhergestellt.

Ansonsten sammele ich zuerst alle Rows und mache nur ein INSERT-Statement, aber das wäre nicht der Sinn einer Db.

Edit: Auch hier schon einmal gefragt, keine Antwort bekommen:

Backup and restore sqlite from disk to memory in Java - Stack Overflow

*** Edit ***

Yea, läuft bei dir, [MENTION=697]mdickie[/MENTION] , ich hab es inzwischen hin bekommen:


import java.io.*;
import java.sql.Connection;
import java.sql.*;
import java.util.*;
import java.util.regex.*;

/**
 * @author CB
 */
public class SelfContainedServerlessEg {

    private static Connection conn = null;
    private static Statement stat = null;

    private static Pattern[] pat = {
        Pattern.compile("japanisch=(\\d+)#"),
        Pattern.compile("'([^']*)'")
    };

    public static void main(String[] args) throws SQLException, ClassNotFoundException, IOException {
        Class.forName("org.sqlite.JDBC");
        //conn = DriverManager.getConnection("jdbc:sqlite:test.sqlite");
        conn = DriverManager.getConnection("jdbc:sqlite::memory:");
        stat = conn.createStatement();
        stat.executeUpdate("restore from test.sqlite");
        stat.close();

        createTable();
        createRows();
        deleteDoppelte();
        createViews();

        stat = conn.createStatement();
        stat.executeUpdate("backup to test.sqlite");
        stat.close();
        conn.close();
    }```

kann nur jedem empfehlen, das so zu machen, verringerte sich bei mir von 40 Sek. auf 4 Sek. ...