Logfile in eine MSSQL Datenbank einlesen

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann musst du das so definieren, indem du einen UNIQUE-Constraint einfuehrst, der alle Spalten umfasst. Danach solltest du zumindest einen Fehler bekommen, wenn du versuchst, die gleiche Zeile zweimal anzulegen. Und dann geht's weiter, du musst dein Skript so umschreiben, dass es entweder alles zeilenweise einfueght, committet oder zurueckrollt, oder du versuchst dich an Mechanismen wie sie hier https://stackoverflow.com/questions/209 ... -not-exist beschrieben werden.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Also müsste man jeder Zeile das Attribut, "unique" geben, damit es eine Fehlermeldung gibt, auf grund derer man dann die eintragung dieser Zeile skippen kann?
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@fredvonfat: nein. Du mußt alle Felder zusammen einen UNIQUE-Constraint geben, weil nur alle Felder zusammen eindeutig sein müssen.

Inzwischen hast Du es ja geschafft, dass Fehlerzeilen und normale Zeilen das gleiche Schema teilen, dann ist aber eine Unterscheidung zwischen Error und Main unsinnig.

Wenn man garantieren kann, dass nachträglich keine weiteren Einträge hinzukommen, wäre das einfachste Kriterium das Datum, so dass man alle Einträge skippen kann, die älter sind als der neuste Eintrag in der Datenbank.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

nzwischen hast Du es ja geschafft, dass Fehlerzeilen und normale Zeilen das gleiche Schema teilen, dann ist aber eine Unterscheidung zwischen Error und Main unsinnig.
Ja, daran hatte ich auch schon gedacht.

Würde es reichen, wenn ich "def insert_entries" anpasse? In "def parse_log" benötige ich die Unterscheidung ja noch.
Wenn man garantieren kann, dass nachträglich keine weiteren Einträge hinzukommen, wäre das einfachste Kriterium das Datum, so dass man alle Einträge skippen kann, die älter sind als der neuste Eintrag in der Datenbank.
Leider reicht das nicht aus, da der Zeitstempel durchaus gleich sein kann, allerdings ist dann mindestens eines der anderen Felder anders.

Auszuschließen ist, dass Zeit und Rufnummer bei zwei aufeinander folgenden Einträgen gleich ist.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann eben der UNIQUE-constraint ueber die notwendigen Spalten. https://stackoverflow.com/questions/347 ... le-columns
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Nach einigem Experimentieren stellt sich heraus, dass es tatsächlich sämtliche Konstellationen gibt, so dass ich die komplette Zeile auswerten muss....

Bei nachfolgenden Code bekomme ich
102, b"Incorrect syntax near 'LIMIT'.DB-Lib error message 20018,

Code: Alles auswählen

with pymssql.connect(server, user, password, database) as conn:
    with conn.cursor(as_dict=True) as cursor:
        cursor.execute('SELECT * FROM main ORDER BY zeit LIMIT 1')
        for row in cursor:
            print("%s %s %s %s %s %s" % 
                    (
                        row['zeit'],
                        row['prom'],
                        row['message'],
                        row['did'],
                        row['rufnummer'],
                        row['site']))
                        
ohne Limit geht es...

Gibt es da eine alternative zu?
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wofuer soll das denn gut sein, das limit? Wenn du einen UNIQUE-Constraint hast, fragst du einfach alle Spalten ab, und dann kann genau eine oder keine Zeile zurueckkommen.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@fredvonfat: was versuchst Du denn da mit dem SELECT zu erreichen?
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Den letzten Eintrag in der DB mit den logfile lines vergleichen.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Warum den letzten? Ich denke das reicht nicht, sondern es koennen mehrere pro Zeitpunkt sein? Hast du vorher doch noch extra ausgefuehrt?

Und wenn dich nur der neueste interessiert, sollte eigentlich MAX(zeit) klappen. Das gibt dann nur eine Zeile als Ergebnis.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Ich such irgendwie ne Lösung, so dass nicht jedes mal die komplette Tabelle untersucht werden muss. Da können im Laufe der Zeit viele hundert tausende Zeilen drin sein.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Eigentlich muss ich nur die Einträge vom gleichen Tag vergleichen, denn am nächsten tag ist es wieder ein neues logfile.....
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Ich bin ja für praktische Lösungen.
Ich würde mir nach der erfolgreichen Speicherung der Daten merken, wieviele Zeilen ich aus der Log-Datei gelesen wurden, und diese beim nächsten Mal skippen.

Das mit den Constraints würde ich aber trotzdem machen (auch wenn das teuer ist) um am kleinsten Punkt ausschließen zu können, dass eine Zeile doppelt hinein rutscht.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Constraints hab ich schon über das SQL Management Studio eingerichtet. Das funktioniert schon.
Das mit den Zeilen merken erscheint mir eine gute Idee, die steht ja mit im logfile.
Habe nur noch keine Idee, wie das merken funktioniert.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Man könnte sie in eine Datenbank schreiben und dann nachschauen, ob die Zeilen schon drin sind 🤔🤔🤔

Ernsthaft: Datenbanken sind für sowas gemacht. Pragmatisch ist nicht sich irgendwelchen kruden Kriterien auszudenken, nach denen man da voreilig optimiert. Sondern die DB ihren Job machen zu lassen. Der unique constraint sollte bei voller bei voller Abfrage eigentlich auch einen Index enthalten, so das die Antwort ob die Zeile enthalten ist effizient berechnet wird.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Danke für die super Anregungen.
Jetzt habe ich wieder viele Hausaufgaben.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Dann musst du das so definieren, indem du einen UNIQUE-Constraint einfuehrst, der alle Spalten umfasst. Danach solltest du zumindest einen Fehler bekommen, wenn du versuchst, die gleiche Zeile zweimal anzulegen. Und dann geht's weiter, du musst dein Skript so umschreiben, dass es entweder alles zeilenweise einfueght, committet oder zurueckrollt,
Nach einmal drüber schlafen und grübeln, erscheint mir der Vorschlag von deets am einfachsten realisierbar.

Jedoch fiel mir dabei auf, das ich noch einige verständnisprobleme zu den funktionen habe.

main:
Hier wird "insert_entries" einmalig aufgerufen und die objekte von "parse_log" als parameter übergeben?
Ich komme darauf, weil nach der ersten Zeile gleich ein Abbruch erfolgt wenn die Eintragung dieser ein Fehler verursacht.
Oder wird try so häufig ausgeführt, bis keine Daten mehr von "parse_log" kommen und so lange nichts unerwartetes auftritt?

insert_entries:
Wo wird der Parameter "entries" definiert oder ist dieser direkt von Python gegeben?
Wenn zum start von "insert_entries", alle Objekte von "parse_log" zur Verfügung stehen, scheint diese Funktion, die Menge der Objekte zeilenweise abzuarbeiten und in die Datenbank zu übertragen.
Oder wird auch "insert_entries" so oft aufgerufen, wie erforderlich und bekommt die Objekte zeilenweise serviert?

parse_log :
1. Hier werden die Zeilen des Logfiles verarbeitet, manipuliert und gesammelt in einem Tupel bereitgestellt?
2. Oder geschieht die Bereitstellung zeilenweise und die funktion wird so oft aufgerufen wie notwendig?
Was ich hier im Forum schon gelernt habe ist, dass man eine Funktion dann definiert, wen man den entsprechenden Aufruf häufiger verwendet.
Demnach würde ich hier zu 2. tendieren. Liege ich da richtig?

Wenn "insert_entries" und "parse_log" zeilenweise liefern, dann müsste ich demnach nur in "main" eine "for-Schleife" um "try / except / else" legen und dann sollte der Vorschlag von deets realisiert sein, oder?
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

All diese Fragen sind wirklich absolute Grundlagen von Python. Hast du schon mal das Tutorial durchgearbeitet? Zu den Kontrollstrukturen if/for/while/try und der Definition von Funktionen und deren Aufruf steht da wirklich alles episch erklaert. Es bringt nichts, wenn du beliebig Annahmen ueber die Art und Weise wie ein Programm funktioniert triffst, und wir die dann einzeln korrigieren muessen. Und wenn du gelernt hast, wie man Funktionen erstellt und aufruft, dann frage ich mich, warum du dich fragst, woher "entries" kommt.

Das einzige, das ein bisschen fortgeschrittener ist, ist parse_log. Das ist dir aber auch schon erklaert worden, dass es sich dabei um einen generator handelt.
fredvonfat
User
Beiträge: 51
Registriert: Mittwoch 12. September 2018, 10:00
Wohnort: Berlin

Ja, ich bin mir bewusst, das ich gravierende Lücken in den Grundlagen zu Python habe.
Kapitelweise hab ich mir ein paar tutorials angeschaut.
Zum Verständnis dessen hilft es mir, wenn ich anhand eines Projektes, antworten auf die entstandenen Fragen bekomme, auch wenn es nur ein ja oder nein ist, oder ein Hinweis auf Quellen für Informationen.
Manchmal stehe ich einfach auf dem Schlauch und brauche nen kleinen Schubs.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Tut mir leid, aber das geht weit ueber das Ausmass von "schubsen" hinaus, die ich hier leisten kann. Vielleicht haben andere da mehr Zeit. Viele deiner Fragen wurden uebrigens schon beantwortet, und auch Quellen genannt. Das nur am Rande.
Antworten