【问题标题】:Executing a MySQL query on command line via os.system in Python在 Python 中通过 os.system 在命令行上执行 MySQL 查询
【发布时间】:2009-08-03 08:36:15
【问题描述】:

我正在尝试将 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 客户端执行此操作

【问题讨论】:

  • 使用 MySQLdb 模块有什么问题?

标签: python mysql shell


【解决方案1】:

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

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

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

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

#!/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)

【讨论】:

    【解决方案2】:

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

    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")
    

    【讨论】:

      【解决方案3】:

      嗯,你可以将mysql模板查询保存在一个配置文件中,然后用ConfigParser解析它:

      配置文件如下所示:

      [mysql query configuration]
      dbhost = 
      db = 
      username = guest
      password = 
      
      [query template]
      template = SELECT Date, SUM(CostUsd).......
      

      或者您可以将其存储到一个单独的文件中,然后使用标准的 open(filename).read 等读取它。 如果你认为以后查询会变得更复杂,那么配置文件的方式可能更易于管理和理解,但差别不大。

      要获取日期作为参数,可以使用 sys.argv,或者像optparse 这样的库

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-07
        • 2013-07-06
        • 2016-05-09
        • 1970-01-01
        • 2014-02-27
        相关资源
        最近更新 更多