Ich habe ein kleines Programm geschrieben, um CSV Dateien mit SQL Befehlen von der Kommenadozeile ad-hoc zu untersuchen: sql4csv. Ziel war es ein Query wie das folgende von der Bash Kommandozeile ab zu setzen:
> scq select distinct author from books.csv
Das Ergebnis wird dann wieder in Form einer CSV Datei ausgegeben:
author Douglas Adams Terry Pratchet
Bei der Entwicklung habe ich Wert auf einfache Verwendung gelegt. So soll es nicht nötig sein die Werttypen (integer, numeric oder Datumsangaben) der Spalten vor der Benutzung. Vielmehr soll dies das Tools möglichst selbst erkennen und die Spaltentypen entsprechend anpassen. Damit sollen auch Abfragen wie
> scq select ABC from xyz.csv where VALUE < 10
möglich sind.
Für integer und numeric Typen ist das auch ohne grosse Probleme möglich. Kniffelig ist es bei Datums- und Zeitabgaben. Hier gibt es zig unterschiedliche Formate. Deswegen habe ich mich für einen pragmatischen Weg der Umsetzung entschieden: es werden aktuell die drei für mich wichtigsten Datumsformate für den Gregorianischen Kalender unterstützt
Datums- und Zeitformate
- Y - steht für das Jahr. Jahre werden immer vierstellig angegeben
- M - steht für den Monat
- D - steht für den Tag im Monat
- h - steht für Stunden
- m - steht für Minuten
- s - steht für Sekunden
Datumsangaben
- YYYY-MM-TT
ISO 8601 ähnlich.
Unterstützt wird auch eine sogenannte lazy Schreibweise, bei der auf einen führende Null (0) bei Zahlen unter 10 verzichtet werden kann. Dies bedeutet, dass auch ein Datum 2016-9-6 als 6. September 2016 erkannt wird.
- MM/DD/YYYY
Amerikanische Datumsschreibweise.
Wie bei der ISO 8601 Schreibweise wird auch hier eine lazy Schreibweise ohne führende Null unterstützt.
- DD.MM.YYYY
Entspricht der numerischen DIN 5008.
Wie bei der ISO 8601 Schreibweise wird auch hier eine lazy Schreibweise ohne führende Null unterstützt.
Zeitangaben
Zeiten werden immer mit einem Doppelpunkt getrennt. Dabei unterstützt sql4csv nur die Reihenfolge hh:mm:ss. Dieses Format allerdings auch lazy, also ohne führende Null und die Sekunde kann ebenfalls weggelassen werden. In diesem Fall wird die Sekunde intern auf Null gesetzt..
Zeitstempel
Zeitstempel sind eine Kombination aus Datum und Zeit. sql4csv erlaubt alle Kombinationen von Datums- und Zeitangaben. Dabei kann als Separator das ISO 8601 T verwendet werden oder ein Leerzeichen.
Beispiele
- 2016-7-3 1:16
- 8/30/1969T23:5:07
- 11.11.2011 11:11:11
Implementierung
sql4csv wurde in Java 8 implementiert. Ich habe es auch geschrieben, um die neuen Sprachfeatures von Java 8 in der Praxis zu lernen und anzuwenden. So kommen intensiv Lambdas zum Einsatz und auch Methodenreferenzen. Die gesamte Datums- und Zeitbearbeitung basiert auf dem java.time
API.
Als Datenbank verwende ich Derby als in-memory Datenbank. Ich verwende nicht SQLite - wie dies einige andere Implementierungen für ein solches Tool tun - da dies entweder eine vorhandene Installation von SQLite voraussetzt oder ich die Binaries für die unterschiedlichsten Plattformen mitliefern müsste. Das ist zu kompliziert und wird der Einfachheit des Werkzeuges nicht gerecht.
Probleme
SQL Queries und die
> scq select * from books.csv where author = 'Douglas Adams '
ist nicht möglich. Die Bash ersetzt das * Zeichen durch die Dateinamen des aktuellen Verzeichnisses. Als Abhilfe kann das Hilfstool scq-cols verwendet werden:
> scq select $(scq-cols books.csv) from books.csv where author = 'Douglas Adams'
Das ist nicht schön, aber eine pragmatische Lösung. Nach einigen malen benutzen hatte ich mich daran gewöhnt.
Ebenso müssen runde Klammern (z.B. für Gruppierungen) und spitze Klammern <> für grösser und kleiner Vergleiche durch eine Backslash (\) maskiert werden. Insgesamt kann durch diese Einschränkungen die Lesbarkeit des Queries beeinträchtigt werden.
Download und Installation
Im sql4csv Repository auf Github findet ihr eine Download und Installationsanleitung, um das Tools selbst einmal ausprobieren zu können.