在Python中通过os.system在命令行上执行MySQL查询

时间:2009-08-03 08:36:16

标签: python mysql shell

我正在尝试将while循环中的'day'传递给sql语句,然后将其传递到MySQL命令行以使用-e执行

我不能使用DB模块或其他python库来访问MySQL,它需要通过命令行完成。看起来我可能需要在连接到sql之前将日期转换为字符串?

#!/usr/bin/python

import datetime


a = datetime.date(2009, 1, 1)
b = datetime.date(2009, 7, 1)
one_day = datetime.timedelta(1)

day = a

while day <= b:
 print day

 sql="SELECT Date,SUM(CostUsd) FROM Stats d WHERE d.Date = " + day + " GROUP BY Date"

 print "SELECT Date,SUM(CostUsd) FROM Stats d WHERE d.Date = " + day + " GROUP BY Date"

 os.system('mysql -h -sN -u -p -e " + sql + " > /home/output/DateLoop-" + day + ".txt db')
 day += one_day

是否可以将其设置为将SQL作为输入文件并将该日作为字符串传递给它?查询可能会变得更复杂,甚至需要多次查询,这可能会成为尝试传递为字符串的问题。

我对任何想法持开放态度,只要查询可以将日期作为输入,使用相同的日期命名输出文件,并从命令行MySQL客户端

执行此操作

3 个答案:

答案 0 :(得分:3)

以下代码可能对您有所帮助。它并不特别令人兴奋,故意简单。这不是许多程序员解决这个问题的方式,但如果没有更多信息,它似乎可以满足您的要求。

我还假设你是python的新手;如果我错了,请随意忽略这篇文章。

  • 允许在命令行上传递数据库凭据,输出目录和日期(开始和结束)。
  • 使用子进程代替os.system。 Subprocess提供了从python调用外部可执行文件的首选机制。这段代码使用最简单的代码; call()因为它类似于os.system()
  • 使用optparse处理命令行参数。虽然代码肯定更长,更冗长,但您将来更容易对arg处理进行添加和修改。很明显发生了什么(代码总是比编写代码更频繁地阅读。)
  • 命令行设置仅在脚本执行时运行,因为它在__main__块中。由于脚本的“逻辑”在main()方法中,您也可以导入它并从另一个源提供选项对​​象(和arg列表)。

如果您不需要在单独的文件中输出每个日期,则可以让数据库引擎计算SUM()并按日期对它们进行分组。你可以在一次db调用中得到所有的总和,这样会更快,并且可以产生更简单的代码。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import datetime
import os
import subprocess
from optparse import OptionParser

SQL = """SELECT d.Date, SUM(d.CostUsd) FROM Stats d WHERE d.Date = '%s' GROUP BY d.Date"""


def get_stats(options, dateobj):
    """Return statistics for the date of `dateobj`"""
    _datestr = dateobj.strftime('%Y-%m-%d')
    sql = SQL % _datestr
    filepath = os.path.join(options.outdir, 'DateLoop-%s.txt' % _datestr)
    return subprocess.call('mysql -h %s -u %s -p -sN -e "%s" db > %s' % (options.dbhost, options.dbuser, sql, filepath), shell=True)


def main(options, args):
    """"""
    _date = options.startdate
    while _date <= options.enddate:
        rs = get_stats(options, _date)
        _date += datetime.timedelta(days=1)


if __name__ == '__main__':
    parser = OptionParser(version="%prog 1.0")
    parser.add_option('-s', '--startdate', type='string', dest='startdate', 
        help='the start date (format: yyyymmdd)')

    parser.add_option('-e', '--enddate', type='string', dest='enddate', 
        help='the end date (format: yyyymmdd)')

    parser.add_option('--output', type='string', dest='outdir', default='/home/output/', 
        help='target directory for output files')

    parser.add_option('--dbhost', type='string', dest='dbhost', default='myhost', 
        help='SQL server address')

    parser.add_option('--dbuser', type='string', dest='dbuser', default='dbuser', 
        help='SQL server user')

    options, args = parser.parse_args()

    ## Process the date args
    if not options.startdate:
        options.startdate = datetime.datetime.today()
    else:
        try:
            options.startdate = datetime.datetime.strptime('%Y%m%d', options.startdate)
        except ValueError:
            parser.error("Invalid value for startdate (%s)" % options.startdate)

    if not options.enddate:
        options.enddate = options.startdate + datetime.timedelta(days=7)
    else:
        try:
            options.enddate = datetime.datetime.strptime('%Y%m%d', options.enddate)
        except ValueError:
            parser.error("Invalid value for enddate (%s)" % options.enddate)

    main(options, args)

答案 1 :(得分:1)

尝试显式格式化并引用结果字符串:

sql = "....WHERE d.Date = '" + date.isoformat() + "' GROUP BY ..."

os.system调用的引用很乱,重定向看起来很奇怪(如果它不是拼写错误)

os.system("mysql db -h -sN -u -p -e '" + sql + "' > /home/output/DateLoop-" + day + ".txt")

答案 2 :(得分:0)

好吧,你可以将mysql模板查询保存在配置文件中并用ConfigParser解析:

配置文件如下所示:

[mysql query configuration]
dbhost = 
db = 
username = guest
password = 

[query template]
template = SELECT Date, SUM(CostUsd).......

或者您可以将其存储到单独的文件中,然后使用标准的open(filename).read等读取它。 如果您认为查询将来会变得更加复杂,那么配置文件方法可能更容易管理和理解,但这并没有太大区别。

要将日期作为参数,您可以使用sys.argv或类似optparse的库