Выполнение MySQL-запроса в командной строке через os.system в Python - PullRequest
1 голос
/ 03 августа 2009

Я пытаюсь передать 'day' из цикла while в оператор 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 ]

3 голосов
/ 13 октября 2009

Код ниже может помочь вам. Это не особенно интересно и намеренно просто. Это не так, как многие программисты решают эту проблему, но без дополнительной информации, кажется, она отвечает вашим требованиям.

Я также сделал предположение, что вы новичок в Python; Если я не прав, не стесняйтесь игнорировать этот пост.

  • Разрешает передачу учетных данных базы данных, выходного каталога и дат (начало и конец) в командной строке.
  • Использует подпроцесс вместо os.system. Подпроцесс предоставляет предпочтительные механизмы для вызова внешних исполняемых файлов из python. Этот код использует самые простые из них; call () как и os.system ()
  • Использует optparse для обработки аргументов командной строки. Хотя код, безусловно, более длинный и более подробный, вам будет легче вносить дополнения и модификации в обработку arg в будущем. Также довольно ясно, что происходит (и код всегда читается гораздо чаще, чем пишется).
  • Настройка командной строки выполняется только тогда, когда скрипт выполняется так, как он находится внутри блока __main__. Поскольку «логика» сценария находится в методе main (), вы также можете импортировать его и предоставить объект параметров (и список аргументов) из другого источника.

Если вы можете отменить необходимость вывода каждой даты в отдельном файле, вы можете заставить механизм базы данных вычислить 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)
1 голос
/ 03 августа 2009

Попробуйте явно отформатировать и заключить в кавычки полученную строку:

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

Цитаты в системном вызове os.s являются грязными, а перенаправление выглядит странно (если это не опечатка)

os.system("mysql db -h -sN -u -p -e '" + sql + "' > /home/output/DateLoop-" + day + ".txt")
0 голосов
/ 03 августа 2009

Ну, вы можете сохранить запрос шаблона mysql в файле конфигурации и проанализировать его с помощью ConfigParser :

Файл конфигурации будет выглядеть так:

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

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

или вы можете просто сохранить его в отдельном файле, а затем прочитать его со стандартным открытием (имя файла) .read и т. Д. Если вы считаете, что запрос станет более сложным в будущем, подход с использованием файла конфигурации может быть проще для управления и понимания, но это не большая разница.

Чтобы получить дату в качестве параметра, вы можете использовать sys.argv или такую ​​библиотеку, как optparse

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