programing

python MySQLdb를 사용하여 *.sql 파일 실행

css3 2023. 9. 2. 08:43

python MySQLdb를 사용하여 *.sql 파일 실행

는 MySQLdb python 드라이버를 사용하여 *.sql 파일에 저장된 sql 스크립트를 실행할 수 있습니다.노력하고 있었습니다.


cursor.execute(file(PATH_TO_FILE).read())

커서가 작동하지 않습니다.execute는 한 번에 하나의 sql 명령만 실행할 수 있습니다.대신 내 sql 스크립트에는 몇 가지 sql 문이 포함되어 있습니다.또한 저는 노력하고 있었습니다.


cursor.execute('source %s'%PATH_TO_FILE)

그러나 또한 성공하지 못했습니다.

python에서 파일을 실행하기 위해 mysql 프로세스를 시작합니다.

from subprocess import Popen, PIPE
process = Popen(['mysql', db, '-u', user, '-p', passwd],
                stdout=PIPE, stdin=PIPE)
output = process.communicate('source ' + filename)[0]

저도 SQL 파일을 실행해야 했는데, 한 줄에 하나의 문이 없어서 수락된 답변이 제게 효과가 없었습니다.

실행하려는 SQL 파일은 다음과 같습니다.

-- SQL script to bootstrap the DB:
--
CREATE USER 'x'@'%' IDENTIFIED BY 'x';
GRANT ALL PRIVILEGES ON mystore.* TO 'x'@'%';
GRANT ALL ON `%`.* TO 'x'@`%`;
FLUSH PRIVILEGES;
--
--
CREATE DATABASE oozie;
GRANT ALL PRIVILEGES ON oozie.* TO 'oozie'@'localhost' IDENTIFIED BY 'oozie';
GRANT ALL PRIVILEGES ON oozie.* TO 'oozie'@'%' IDENTIFIED BY 'oozie';
FLUSH PRIVILEGES;
--
USE oozie;
--
CREATE TABLE `BUNDLE_ACTIONS` (
  `bundle_action_id` varchar(255) NOT NULL,
  `bundle_id` varchar(255) DEFAULT NULL,
  `coord_id` varchar(255) DEFAULT NULL,
  `coord_name` varchar(255) DEFAULT NULL,
  `critical` int(11) DEFAULT NULL,
  `last_modified_time` datetime DEFAULT NULL,
  `pending` int(11) DEFAULT NULL,
  `status` varchar(255) DEFAULT NULL,
  `bean_type` varchar(31) DEFAULT NULL,
  PRIMARY KEY (`bundle_action_id`),
  KEY `I_BNDLTNS_DTYPE` (`bean_type`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
--

위 파일의 일부 문은 한 줄에 있고 일부 문은 여러 줄에 걸쳐 있습니다(마지막에 있는 CREATE TABLE과 같이).또한 "--"로 시작하는 몇 개의 SQL 인라인 주석 행이 있습니다.

Thomas K가 제안한 것처럼, 저는 성명서에 줄을 묶기 위해 몇 가지 간단한 규칙을 작성해야 했습니다.저는 결국 sql 파일을 실행하는 기능을 갖게 되었습니다.

def exec_sql_file(cursor, sql_file):
    print "\n[INFO] Executing SQL script file: '%s'" % (sql_file)
    statement = ""

    for line in open(sql_file):
        if re.match(r'--', line):  # ignore sql comment lines
            continue
        if not re.search(r';$', line):  # keep appending lines that don't end in ';'
            statement = statement + line
        else:  # when you get a line ending in ';' then exec statement and reset for next statement
            statement = statement + line
            #print "\n\n[DEBUG] Executing SQL statement:\n%s" % (statement)
            try:
                cursor.execute(statement)
            except (OperationalError, ProgrammingError) as e:
                print "\n[WARN] MySQLError during execute statement \n\tArgs: '%s'" % (str(e.args))

            statement = ""

개선의 여지가 있다고 생각합니다만, 현재로서는 저에게 꽤 효과가 있습니다.누군가 그것을 유용하게 생각하길 바랍니다.

이것은 저에게 효과가 있었습니다.

with open('schema.sql') as f:
    cursor.execute(f.read().decode('utf-8'), multi=True)
for line in open(PATH_TO_FILE):
    cursor.execute(line)

이는 파일에 한 줄당 하나의 SQL 문이 있다고 가정합니다.그렇지 않으면 줄을 함께 연결하기 위한 규칙을 작성해야 합니다.

분석 할 수 또은 "MySQL"을 입니다.os.system명령어는 python 를 실행합니다.

from os import system
USERNAME = "root"
PASSWORD = "root"
DBNAME = "pablo"
HOST = "localhost"
PORT = 3306
FILE = "file.sql"
command = """mysql -u %s -p"%s" --host %s --port %s %s < %s""" %(USERNAME, PASSWORD, HOST, PORT, DBNAME, FILE)
system(command)

를 들어 " 를어 " " 열가 " 을다 " 문니 " 석변 " " 문자열 변수가 때 합니다.;-)그것 안에 또는 당신이 확인한다면.;마지막 캐릭터로, 만약 당신이 나중에 댓글이 있다면.SELECT * FROM foo_table; # selecting data

여기에 있는 많은 대답들은 심각한 결함을 가지고 있습니다.

먼저, 오픈 엔드 SQL 스크립트를 직접 구문 분석하려고 하지 마십시오!이 작업을 쉽게 수행할 수 있다고 생각하면 SQL이 얼마나 강력하고 복잡한 작업인지 알 수 없습니다.심각한 SQL 스크립트에는 여러 줄에 걸친 문 및 절차 정의가 포함됩니다.스크립트 중간에 명시적으로 구분 기호를 선언하고 변경하는 것도 일반적입니다.소스 명령을 서로 중첩할 수도 있습니다.여러 가지 이유로 인해 MySQL 클라이언트를 통해 스크립트를 실행하고 무거운 작업을 처리할 수 있도록 해야 합니다.그것을 재발명하려고 하는 것은 걱정스러운 위험과 엄청난 시간 낭비입니다.아마도 당신이 이 대본들을 쓰는 유일한 사람이고, 당신이 그것으로 벗어날 수 있는 세련된 것을 쓰지 않는다면, 왜 당신 자신을 그런 정도로 제한합니까?기계가 생성한 스크립트나 다른 개발자가 작성한 스크립트는 어떻습니까?

@jdferreira의 대답은 올바른 방향으로 가고 있지만, 문제와 약점도 있습니다.가장 중요한 것은 연결 매개 변수를 프로세스로 전송함으로써 보안 구멍이 열리고 있다는 것입니다.

복사 및 붙여넣기 기능을 위한 솔루션/예시입니다.저의 확장된 논의는 다음과 같습니다.

먼저 별도의 구성 파일을 만들어 사용자 이름과 암호를 저장합니다.

db-sys.cfg

[client]
user     = XXXXXXX
password = YYYYYYY

Python 프로세스가 읽을 수 있도록 올바른 파일 시스템 권한을 적용합니다. 그러나 아무도 볼 수 없습니다.

그런 다음 이 Python을 사용합니다(이 예에서는 creds 파일이 py 스크립트에 인접합니다).

#!/usr/bin/python

import os
import sys
import MySQLdb
from subprocess import Popen, PIPE, STDOUT

__MYSQL_CLIENT_PATH = "mysql"

__THIS_DIR = os.path.dirname( os.path.realpath( sys.argv[0] ) )

__DB_CONFIG_PATH    = os.path.join( __THIS_DIR, "db-creds.cfg" )
__DB_CONFIG_SECTION = "client"

__DB_CONN_HOST = "localhost"
__DB_CONN_PORT = 3306

# ----------------------------------------------------------------

class MySqlScriptError( Exception ):

    def __init__( self, dbName, scriptPath, stdOut, stdErr ):
        Exception.__init__( self )
        self.dbName = dbName
        self.scriptPath = scriptPath
        self.priorOutput = stdOut
        self.errorMsg = stdErr                
        errNumParts = stdErr.split("(")        
        try : self.errorNum = long( errNumParts[0].replace("ERROR","").strip() )
        except: self.errorNum = None        
        try : self.sqlState = long( errNumParts[1].split(")")[0].strip() )
        except: self.sqlState = None

    def __str__( self ): 
        return ("--- MySqlScriptError ---\n" +
                "Script: %s\n" % (self.scriptPath,) +
                "Database: %s\n" % (self.dbName,) +
                self.errorMsg ) 

    def __repr__( self ): return self.__str__()

# ----------------------------------------------------------------

def databaseLoginParms() :        
    from ConfigParser import RawConfigParser
    parser = RawConfigParser()
    parser.read( __DB_CONFIG_PATH )   
    return ( parser.get( __DB_CONFIG_SECTION, "user" ).strip(), 
             parser.get( __DB_CONFIG_SECTION, "password" ).strip() )

def databaseConn( username, password, dbName ):        
    return MySQLdb.connect( host=__DB_CONN_HOST, port=__DB_CONN_PORT,
                            user=username, passwd=password, db=dbName )

def executeSqlScript( dbName, scriptPath, ignoreErrors=False ) :       
    scriptDirPath = os.path.dirname( os.path.realpath( scriptPath ) )
    sourceCmd = "SOURCE %s" % (scriptPath,)
    cmdList = [ __MYSQL_CLIENT_PATH,                
               "--defaults-extra-file=%s" % (__DB_CONFIG_PATH,) , 
               "--database", dbName,
               "--unbuffered" ] 
    if ignoreErrors : 
        cmdList.append( "--force" )
    else:
        cmdList.extend( ["--execute", sourceCmd ] )
    process = Popen( cmdList 
                   , cwd=scriptDirPath
                   , stdout=PIPE 
                   , stderr=(STDOUT if ignoreErrors else PIPE) 
                   , stdin=(PIPE if ignoreErrors else None) )
    stdOut, stdErr = process.communicate( sourceCmd if ignoreErrors else None )
    if stdErr is not None and len(stdErr) > 0 : 
        raise MySqlScriptError( dbName, scriptPath, stdOut, stdErr )
    return stdOut

테스트를 수행하려면 다음을 추가합니다.

if __name__ == "__main__": 

    ( username, password ) = databaseLoginParms()
    dbName = "ExampleDatabase"

    print "MySQLdb Test"
    print   
    conn = databaseConn( username, password, dbName )
    cursor = conn.cursor()
    cursor.execute( "show tables" )
    print cursor.fetchall()
    cursor.close()
    conn.close()
    print   

    print "-----------------"
    print "Execute Script with ignore errors"
    print   
    scriptPath = "test.sql"
    print executeSqlScript( dbName, scriptPath, 
                            ignoreErrors=True )
    print   

    print "-----------------"
    print "Execute Script WITHOUT ignore errors"                            
    print   
    try : print executeSqlScript( dbName, scriptPath )
    except MySqlScriptError as e :        
        print "dbName: %s" % (e.dbName,)
        print "scriptPath: %s" % (e.scriptPath,)
        print "errorNum: %s" % (str(e.errorNum),)
        print "sqlState: %s" % (str(e.sqlState),)
        print "priorOutput:"        
        print e.priorOutput
        print
        print "errorMsg:"
        print e.errorMsg           
        print
        print e
    print   

다음은 적절한 측정을 위해 입력할 sql 스크립트의 예입니다.

test.sql

show tables;
blow up;
show tables;

자, 이제 토론을 좀 하겠습니다.

먼저 이 외부 스크립트 실행과 함께 MySQLDB를 사용하는 방법을 설명하고, 두 가지 모두에 사용할 수 있는 하나의 공유 파일에 자격 증명을 저장합니다.

을 사용하여--defaults-extra-file명령줄에서 연결 매개 변수를 안전하게 전달할 수 있습니다.

둘 중 하나의 조합--forcestdin 스트리밍 소스 명령 또는--execute외부에서 명령을 실행합니다. 스크립트 실행 방법을 지정할 수 있습니다.즉, 오류를 무시하고 계속 실행하거나 오류가 발생하는 즉시 중지합니다.

결과가 돌아오는 순서도 다음과 같이 보존됩니다.--unbuffered그렇지 않으면 stdout 및 stderr 스트림이 순서대로 뒤섞이고 정의되지 않으므로 입력 sql과 비교할 때 무엇이 작동하고 무엇이 작동하지 않았는지 파악하기가 매우 어렵습니다.

Popen 사용하기cwd=scriptDirPath상대 경로를 사용하여 소스 명령을 서로 중첩합니다.스크립트가 모두 동일한 디렉토리(또는 디렉토리와 관련된 알려진 경로)에 있을 경우 최상위 스크립트가 있는 위치와 관련된 디렉토리를 참조합니다.

마지막으로, 저는 무슨 일이 일어났는지에 대해 여러분이 원하는 모든 정보를 담고 있는 예외 수업을 제출했습니다.ignoreErrors 옵션을 사용하지 않는 경우, 오류가 발생하여 스크립트 실행이 중지되었을 때 이러한 예외 중 하나가 파이썬에 느려집니다.

입니다.MySQLdb할 수 있는 , 당신은 1.2.3으로 . 당신은 그냥 전화하면 됩니다.cursor.nextset()반환된 결과 세트를 순환합니다.

db = conn.cursor()
db.execute('SELECT 1; SELECT 2;')

more = True
while more:
    print db.fetchall()
    more = db.nextset()

이에 대한 지원이 사용 가능한지 확인하거나 지원을 사용할 수 없도록 설정하려면 다음과 같은 방법을 사용할 수 있습니다.

MYSQL_OPTION_MULTI_STATEMENTS_ON = 0
MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1

conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON)
# Multiple statement execution here...
conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_OFF)

SQL 스크립트에 빈 줄이 포함되어 있고 쿼리 문장이 여러 줄에 걸쳐 있을 때 허용된 답변에 문제가 발생합니다.대신 다음 방법을 사용하면 문제가 해결됩니다.

f = open(filename, 'r')
query = " ".join(f.readlines())
c.execute(query)

다른 데이터베이스 드라이버를 사용할 수 있습니까?
예: MySQL의 MySQL Connector/Python 드라이버로 원하는 작업이 가능합니다.

메서드는 전달을 통해 여러 SQL 문을 한 번에 실행할 수 있습니다.Multi=True.

파일의 SQL 문을 세미콜론으로 분할할 필요가 없습니다.

간단한 예(주로번째 링크에서 복사하여 붙여넣기, 파일에서 SQL 읽기를 추가했습니다.):

import mysql.connector

file = open('test.sql')
sql = file.read()

cnx = mysql.connector.connect(user='uuu', password='ppp', host='hhh', database='ddd')
cursor = cnx.cursor()

for result in cursor.execute(sql, multi=True):
  if result.with_rows:
    print("Rows produced by statement '{}':".format(
      result.statement))
    print(result.fetchall())
  else:
    print("Number of rows affected by statement '{}': {}".format(
      result.statement, result.rowcount))

cnx.close()

이를 사용하여 전체 데이터베이스를 SQL 파일로 내보냄으로써 phpMyAdmin에서 생성된 MySQL 덤프를 *.sql 파일에서 데이터베이스로 다시 가져옵니다.

설명 중 하나에서 언급한 것처럼 모든 명령이 세미콜론으로 끝나는 경우 다음 작업을 수행할 수 있습니다.

import mysql.connector
connection = mysql.connector.connect(
    host=host,
    user=user,
    password=password
)

cursor = connection.cursor()

with open(script, encoding="utf-8") as f:
    commands = f.read().split(';')

for command in commands:
    cursor.execute(command)
    print(command)

connection.close()

mysqdump 파일 로드:

for line in open(PATH_TO_FILE).read().split(';\n'):
    cursor.execute(line)

인 은일코조가각코져조드다각니입올다을음드반인을 가져올 조각이 .sql그것은 수출에서 나옵니다. (저는 성공적으로 그것을 Sufficial Pro의 수출과 함께 사용했습니다.)줄 쿼리 및 (multi-line andcomments)을 합니다.#).

  • 주 1: Thomas K의 답변에서 첫 번째 줄을 사용했지만 추가했습니다.
  • 주 2: 초보자의 경우 DB_HOST, DB_PASS 등을 데이터베이스 연결 정보로 대체합니다.

import MySQLdb
from configdb import DB_HOST, DB_PASS, DB_USER, DB_DATABASE_NAME

db = MySQLdb.connect(host=DB_HOST,    # your host, usually localhost
                     user=DB_USER,         # your username
                     passwd=DB_PASS,  # your password
                     db=DB_DATABASE_NAME)        # name of the data base

cur = db.cursor()

PATH_TO_FILE = "db-testcases.sql"

fullLine = ''

for line in open(PATH_TO_FILE):
  tempLine = line.strip()

  # Skip empty lines.
  # However, it seems "strip" doesn't remove every sort of whitespace.
  # So, we also catch the "Query was empty" error below.
  if len(tempLine) == 0:
    continue

  # Skip comments
  if tempLine[0] == '#':
    continue

  fullLine += line

  if not ';' in line:
    continue

  # You can remove this. It's for debugging purposes.
  print "[line] ", fullLine, "[/line]"

  try:
    cur.execute(fullLine)
  except MySQLdb.OperationalError as e:
    if e[1] == 'Query was empty':
      continue

    raise e

  fullLine = ''

db.close()

pexpect 라이브러리를 사용하는 것은 어떻습니까?그 아이디어는 당신이 프로세스를 시작할 수 있다는 것입니다.pexpect.spawn(...) 그 에 특정 패턴이 .process.expect(pattern).

나는 실제로 이것을 사용하여 mysql 클라이언트에 연결하고 몇 가지 sql 스크립트를 실행했습니다.

연결 중:

import pexpect
process = pexpect.spawn("mysql", ["-u", user, "-p"])
process.expect("Enter password")
process.sendline(password)
process.expect("mysql>")

이렇게 하면 암호가 명령줄 매개 변수에 하드 코딩되지 않습니다(보안 위험 제거).

여러 SQL 스크립트 실행:

error = False
for script in sql_scripts:
    process.sendline("source {};".format(script))
    index = process.expect(["mysql>", "ERROR"])

    # Error occurred, interrupt
    if index == 1:
        error = True
        break

if not error:
    # commit changes of the scripts
    process.sendline("COMMIT;")
    process.expect("mysql>")

    print "Everything fine"
else:
    # don't commit + print error message
    print "Your scripts have errors"

항상 전화하는 것을 조심하세요.expect(pattern)일치하지 않으면 시간 초과 오류가 발생합니다.여러 개의 SQL 스크립트를 실행하고 오류가 발생하지 않는 경우에만 변경 사항을 커밋하기 위해 이 코드가 필요했지만 스크립트 하나로 사용 사례에 쉽게 적응할 수 있습니다.

이런 걸 사용할 수도..

def write_data(schema_name: str, table_name: str, column_names: str, data: list):
    try:
        data_list_template = ','.join(['%s'] * len(data))
        insert_query = f"insert into {schema_name}.{table_name} ({column_names}) values {data_list_template}"
        db.execute(insert_query, data)
        conn_obj.commit()
    except Exception as e:
        db.execute("rollback")
        raise e

언급URL : https://stackoverflow.com/questions/4408714/execute-sql-file-with-python-mysqldb