mca*_*ano 7 sql command-line text
我们一直在命令行使用grep,cut,sort,uniq和join来进行数据分析.他们工作得很好,虽然有缺点.例如,您必须为每个工具提供列号.我们经常有宽文件(很多列)和一个列标题,用于给出列名.实际上,我们的文件看起来很像SQL表.我确定有一个驱动程序(ODBC?)将操作分隔的文本文件,以及一些将使用该驱动程序的查询引擎,所以我们可以在我们的文本文件上使用SQL查询.由于进行分析通常是临时的,因此查询新文件(仅使用我在此目录中指定的文件)而不是在某些配置中声明特定表必须是最小化设置.
实际上,最简单的是什么?也就是说,最容易设置和用于应用文本文件的SQL引擎和驱动程序?
David Malcolm编写了一个名为" 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 |
Run Code Online (Sandbox Code Playgroud)
借鉴别人的建议,这里是 sqlite3 的 Python 脚本。有点冗长,但它有效。
我不喜欢必须完全复制文件才能删除标题行,但我不知道如何说服 sqlite3 的 .import 跳过它。我可以创建 INSERT 语句,但这看起来同样糟糕,甚至更糟。
调用示例:
$ sql.py --file foo --sql "从数据中选择 count(*)"
代码:
#!/usr/bin/env python
"""在文本文件上运行 SQL 语句"""
导入操作系统
导入系统
导入getopt
导入临时文件
进口重新
类用法(异常):
def __init__(自身, 消息):
self.msg = 味精
def runCmd(cmd):
如果 os.system(cmd):
打印“运行时出错”+cmd
系统退出(1)
# TODO(dan): 返回实际的退出代码
定义用法():
print >>sys.stderr, "用法: sql.py --file 文件 --sql sql"
def main(argv=None):
如果 argv 为 None:
argv = 系统.argv
尝试:
尝试:
opts, args = getopt.getopt(argv[1:], "h",
[“帮助”,“文件=”,“sql=”])
除了 getopt.error,消息:
提高用法(msg)
除了用法之外,错误:
打印 >>sys.stderr, err.msg
print >>sys.stderr, "如需帮助,请使用 --help"
返回2
文件名 = 无
sql=无
对于 opts 中的 o、a:
if o in ("-h", "--help"):
用法()
返回0
elif o in ("--file"):
文件名=a
elif o in ("--sql"):
sql = 一个
别的:
print "发现意外选项" + o
如果不是文件名:
print >>sys.stderr, "必须给出 --file"
系统退出(1)
如果不是sql:
print >>sys.stderr, "必须给出 --sql"
系统退出(1)
# 获取文件的第一行以进行CREATE语句
#
# 将其余行复制到一个新文件(数据文件)中,以便
# sqlite3可以导入不带头的数据。如果 sqlite3 可以跳过
# 第一行带有 .import,这个副本是不必要的。
foo = 打开(文件名)
数据文件 = tempfile.NamedTemporaryFile()
第一个 = 真
对于 foo.readlines() 中的行:
如果首先:
headers = line.rstrip().split()
第一个 = 假
别的:
打印>>数据文件,行,
数据文件.flush()
#打印数据文件.name
#runCmd("cat %s" % 数据文件.name)
# 创建具有 NUMERIC 亲和力的列,这样如果它们是数字,
# SQL 查询将这样对待它们。
create_statement = "创建表数据(" + ",".join(
映射(lambda x:“`%s`数字”%x,标题))+“);”
cmdfile = tempfile.NamedTemporaryFile()
#打印cmd文件名
打印 >>cmdfile,create_statement
打印 >>cmdfile,".separator ' '"
print >>cmdfile,".import '" + datafile.name + "' data"
打印>>cmdfile,sql +“;”
cmdfile.flush()
#runCmd("cat %s" % cmdfile.name)
runCmd("cat %s | sqlite3" % cmdfile.name)
如果 __name__ == "__main__":
系统退出(主())