Механизм SQL-запросов для текстовых файлов в Linux? - PullRequest
7 голосов
/ 22 апреля 2009

Мы используем grep, cut, sort, uniq и join все время в командной строке для анализа данных. Они отлично работают, хотя есть и недостатки. Например, вы должны указать номера столбцов для каждого инструмента. У нас часто бывают широкие файлы (много столбцов) и заголовок столбца, который дает имена столбцов. На самом деле наши файлы очень похожи на таблицы SQL. Я уверен, что есть драйвер (ODBC?), Который будет работать с текстовыми файлами с разделителями, и некоторый механизм запросов, который будет использовать этот драйвер, поэтому мы могли бы просто использовать запросы SQL для наших текстовых файлов. Поскольку анализ обычно выполняется нерегулярно, для запроса новых файлов потребуется минимальная настройка (просто используйте файлы, указанные в этом каталоге), а не для объявления определенных таблиц в некоторых конфигурациях.

Практически говоря, что самое простое? То есть механизм и драйвер SQL, которые проще всего настроить и использовать для применения к текстовым файлам?

Ответы [ 6 ]

5 голосов
/ 08 апреля 2014

q - запуск SQL напрямую для файлов CSV или TSV:

https://github.com/harelba/q

5 голосов
/ 24 апреля 2009

Дэвид Малкольм написал небольшой инструмент с именем " squeal " (ранее "show"), который позволяет использовать синтаксис командной строки, подобный SQL, для разбора текстовых файлов различных форматы, включая CSV.

Пример на домашней странице Squeal:

$ squeal "count(*)", source from /var/log/messages* group by source order by "count(*)" desc
count(*)|source              |
--------+--------------------+
1633    |kernel              |
1324    |NetworkManager      |
98      |ntpd                |
70      |avahi-daemon        |
63      |dhclient            |
48      |setroubleshoot      |
39      |dnsmasq             |
29      |nm-system-settings  |
27      |bluetoothd          |
14      |/usr/sbin/gpm       |
13      |acpid               |
10      |init                |
9       |pcscd               |
9       |pulseaudio          |
6       |gnome-keyring-ask   |
6       |gnome-keyring-daemon|
6       |gnome-session       |
6       |rsyslogd            |
5       |rpc.statd           |
4       |vpnc                |
3       |gdm-session-worker  |
2       |auditd              |
2       |console-kit-daemon  |
2       |libvirtd            |
2       |rpcbind             |
1       |nm-dispatcher.action|
1       |restorecond         |
3 голосов
/ 23 апреля 2009

Отбросив чужое предложение, вот скрипт Python для sqlite3. Немного многословно, но это работает.

Мне не нравится полностью копировать файл, чтобы удалить строку заголовка, но я не знаю, как еще убедить sqlite3 .import пропустить его. Я мог бы создать операторы INSERT, но это выглядит так же плохо, если не хуже.

Пример вызова:

$ sql.py --file foo --sql "select count(*) from data"

код:

#!/usr/bin/env python

"""Run a SQL statement on a text file"""

import os
import sys
import getopt
import tempfile
import re

class Usage(Exception):
    def __init__(self, msg):
        self.msg = msg

def runCmd(cmd):
    if os.system(cmd):
        print "Error running " + cmd
        sys.exit(1)
        # TODO(dan): Return actual exit code

def usage():
    print >>sys.stderr, "Usage: sql.py --file file --sql sql"

def main(argv=None):
    if argv is None:
        argv = sys.argv

    try:
        try:
            opts, args = getopt.getopt(argv[1:], "h",
                                       ["help", "file=", "sql="])
        except getopt.error, msg:
            raise Usage(msg)
    except Usage, err:
        print >>sys.stderr, err.msg
        print >>sys.stderr, "for help use --help"
        return 2

    filename = None
    sql = None
    for o, a in opts:
        if o in ("-h", "--help"):
            usage()
            return 0
        elif o in ("--file"):
            filename = a
        elif o in ("--sql"):
            sql = a
        else:
            print "Found unexpected option " + o

    if not filename:
        print >>sys.stderr, "Must give --file"
        sys.exit(1)
    if not sql:
        print >>sys.stderr, "Must give --sql"
        sys.exit(1)

    # Get the first line of the file to make a CREATE statement
    #
    # Copy the rest of the lines into a new file (datafile) so that
    # sqlite3 can import data without header.  If sqlite3 could skip
    # the first line with .import, this copy would be unnecessary.
    foo = open(filename)
    datafile = tempfile.NamedTemporaryFile()
    first = True
    for line in foo.readlines():
        if first:
            headers = line.rstrip().split()
            first = False
        else:
            print >>datafile, line,
    datafile.flush()
    #print datafile.name
    #runCmd("cat %s" % datafile.name)
    # Create columns with NUMERIC affinity so that if they are numbers,
    # SQL queries will treat them as such.
    create_statement = "CREATE TABLE data (" + ",".join(
        map(lambda x: "`%s` NUMERIC" % x, headers)) + ");"

    cmdfile = tempfile.NamedTemporaryFile()
    #print cmdfile.name
    print >>cmdfile,create_statement
    print >>cmdfile,".separator ' '"
    print >>cmdfile,".import '" + datafile.name + "' data"
    print >>cmdfile, sql + ";"
    cmdfile.flush()
    #runCmd("cat %s" % cmdfile.name)
    runCmd("cat %s | sqlite3" % cmdfile.name)

if __name__ == "__main__":
    sys.exit(main())
3 голосов
/ 22 апреля 2009

Может быть, написать сценарий, который создает экземпляр SQLite (возможно, в памяти), импортирует ваши данные из файла / стандартного ввода (принимая формат ваших данных), выполняет запрос, а затем завершает работу?

В зависимости от объема данных производительность может быть приемлемой.

2 голосов
/ 22 апреля 2009

MySQL имеет механизм хранения CVS , который может делать то, что вам нужно, если ваши файлы являются файлами CSV.

В противном случае вы можете использовать mysqlimport для импорта текстовых файлов в MySQL. Вы можете создать оболочку для mysqlimport, которая вычисляет столбцы и т. Д. И создает необходимую таблицу.

Вы также можете использовать DBD :: AnyData , модуль Perl, который позволяет вам получать доступ к текстовым файлам, например, к базе данных.

Тем не менее, это звучит так, как будто вы действительно должны смотреть на использование базы данных. Действительно ли проще хранить табличные данные в текстовых файлах?

0 голосов
/ 04 июля 2010

Я использовал Microsoft LogParser для запроса файлов CSV несколько раз ... и это служит цели. Было удивительно видеть такой полезный инструмент от M $, который тоже бесплатно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...