programing

python에서 여러 sql 문을 실행할 수 있는 방법을 제안하시겠습니까?

css3 2023. 10. 7. 12:05

python에서 여러 sql 문을 실행할 수 있는 방법을 제안하시겠습니까?

python에서 다음과 같은 것을 실행하는 제안된 방법은 무엇입니까?

self.cursor.execute('SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS %s; SET FOREIGN_KEY_CHECKS=1' % (table_name,))

를 들어,이 세 , .self.cursor.execute(...)진술? 이외에 사용해야 할 특정한 방법이 있습니까 이외해야 할 ?cursor.execute(...)이와 같은 일을 하는 것, 또는 이것을 하는 데 제안된 실천 방법은 무엇입니까?현재 제가 가지고 있는 코드는 다음과 같습니다.

self.cursor.execute('SET FOREIGN_KEY_CHECKS=0;')
self.cursor.execute('DROP TABLE IF EXISTS %s;' % (table_name,))
self.cursor.execute('SET FOREIGN_KEY_CHECKS=1;')
self.cursor.execute('CREATE TABLE %s select * from mytable;' % (table_name,))

보시다시피, 모든 것이 따로따로 운영됩니다. 이 좋은 인지 아닌지 잘 (위의 하는 가장 좋은 그래서 저는 이것이 좋은 생각인지 아닌지 확신할 수 없습니다.(아니면 위의 작업을 수행하는 가장 좋은 방법은 무엇인지)..BEGIN...END?

저장 프로시저를 만듭니다.

DROP PROCEDURE IF EXISTS CopyTable;
DELIMITER $$
CREATE PROCEDURE CopyTable(IN _mytable VARCHAR(64), _table_name VARCHAR(64))
BEGIN
    SET FOREIGN_KEY_CHECKS=0;
    SET @stmt = CONCAT('DROP TABLE IF EXISTS ',_table_name);
    PREPARE stmt1 FROM @stmt;
    EXECUTE stmt1;
    SET FOREIGN_KEY_CHECKS=1;
    SET @stmt = CONCAT('CREATE TABLE ',_table_name,' as select * from ', _mytable);
    PREPARE stmt1 FROM @stmt;
    EXECUTE stmt1;
    DEALLOCATE PREPARE stmt1;
END$$
DELIMITER ;

그리고 나서 그냥 달려라:

args = ['mytable', 'table_name']
cursor.callproc('CopyTable', args)

단순하고 모듈식으로 유지할 수 있습니다.물론 당신은 일종의 오류 검사를 해야 하며 심지어 저장된 프로시저가 성공 또는 실패를 나타내는 코드를 반환하도록 할 수도 있습니다.

의 문서에서, 그들은 다음을 사용할 것을 제안합니다.multi=True매개 변수:

operation = 'SELECT 1; INSERT INTO t1 VALUES (); SELECT 2'
for result in cursor.execute(operation, multi=True):
    ...

모듈의 소스 코드에서 다른 예를 찾을 수 있습니다.

나는 그 어떤 것에도 의지하지 않을 것입니다.multi=Trueexecute- 합니다.;문자열 리터럴에 포함될 수 있는 문자입니다.가장 입니다라는입니다.execute_multiplea, 를 합니다.rollback_on_error하나의 문에서 예외가 발생할 경우 수행할 작업을 결정하는 매개 변수입니다.

PyMySQLDB PyMySQLDB 에으로 SQL 합니다에서.autocommit=0, 마치 처럼, , 어쨌든, 그 가정은 아래의 코드를 유지합니다. 않다면,1. 1.은을 설정하고, 1.다를 .autocommit=0연결 후에 또는 2.하여 이 코드를 수정하여 다음과 같이 트랜잭션을 시작합니다에 따라 합니다.try

def execute_multiple(conn, statements, rollback_on_error=True):
    """
    Execute multiple SQL statements and returns the cursor from the last executed statement.

    :param conn: The connection to the database
    :type conn: Database connection

    :param statements: The statements to be executed
    :type statements: A list of strings

    :param: rollback_on_error: Flag to indicate action to be taken on an exception
    :type rollback_on_error: bool

    :returns cursor from the last statement executed
    :rtype cursor
    """

    try:
        cursor = conn.cursor()
        for statement in statements:
            cursor.execute(statement)
            if not rollback_on_error:
                conn.commit() # commit on each statement
    except Exception as e:
        if rollback_on_error:
            conn.rollback()
        raise
    else:
        if rollback_on_error:
            conn.commit() # then commit only after all statements have completed successfully

또한 매개변수 목록과 함께 준비된 문을 처리하는 버전을 가질 수도 있습니다.

def execute_multiple_prepared(conn, statements_and_values, rollback_on_error=True):
    """
    Execute multiple SQL statements and returns the cursor from the last executed statement.

    :param conn: The connection to the database
    :type conn: Database connection

    :param statements_and_values: The statements and values to be executed
    :type statements_and_values: A list of lists. Each sublist consists of a string, the SQL prepared statement with %s placeholders, and a list or tuple of its parameters

    :param: rollback_on_error: Flag to indicate action to be taken on an exception
    :type rollback_on_error: bool

    :returns cursor from the last statement executed
    :rtype cursor
    """

    try:
        cursor = conn.cursor()
        for s_v in statements_and_values:
            cursor.execute(s_v[0], s_v[1])
            if not rollback_on_error:
                conn.commit() # commit on each statement
    except Exception as e:
        if rollback_on_error:
            conn.rollback()
        raise
    else:
        if rollback_on_error:
            conn.commit() # then commit only after all statements have completed successfully
        return cursor # return the cursor in case there are results to be processed

예를 들어,

cursor = execute_multiple_prepared(conn, [('select * from test_table where count = %s', (2000,))], False)

인정하건대, 위 호출에는 매개 변수가 포함된 SQL이 하나만 준비되어 있었습니다.

아름다움은 보는 사람의 눈에 있기 때문에 어떤 것을 하는 가장 좋은 방법은 어떻게 측정해야 하는지 우리에게 명시적으로 말하지 않는 한 주관적입니다.제가 볼 수 있는 가상 옵션은 세 가지입니다.

  1. 을 합니다.multiMySQLCursor 옵션(이상적이지 않음)
  2. 쿼리를 여러 행으로 유지
  3. 쿼리를 한 행에 보관

또는 불필요한 작업을 방지하기 위해 쿼리를 변경할 수도 있습니다.


multi옵션 MySQL 문서는 꽤 명확합니다.

multi를 True로 설정하면 execute()는 연산 문자열에 지정된 여러 문을 실행할 수 있습니다.각 문의 결과를 처리할 수 있는 반복기를 반환합니다.그러나 이 경우 모수를 사용하는 것은 잘 작동하지 않으며,문을 자체적으로 실행하는 것이 좋습니다.


옵션 2. 및 3. 코드를 보는 방법에 대한 순수한 선호 사항입니다.다가(가) .autocommit=FALSE됩니다를 합니다.cursor.execute(...)단일 트랜잭션에 호출합니다. 두 즉,다입니다

self.cursor.execute('SET FOREIGN_KEY_CHECKS=0;')
self.cursor.execute('DROP TABLE IF EXISTS %s;' % (table_name,))
self.cursor.execute('SET FOREIGN_KEY_CHECKS=1;')
self.cursor.execute('CREATE TABLE %s select * from mytable;' % (table_name,))

self.cursor.execute(
    'SET FOREIGN_KEY_CHECKS=0;'
    'DROP TABLE IF EXISTS %s;' % (table_name,)
    'SET FOREIGN_KEY_CHECKS=1;'
    'CREATE TABLE %s select * from mytable;' % (table_name,)
)

파이썬 3.6은 굉장히 우아한 f-스트링을 선보였는데, 사용할 수 있다면 사용해야 합니다.:)

self.cursor.execute(
    'SET FOREIGN_KEY_CHECKS=0;'
    f'DROP TABLE IF EXISTS {table_name};'
    'SET FOREIGN_KEY_CHECKS=1;'
    f'CREATE TABLE {table_name} select * from mytable;'
)

행을 조작하기 시작할 때는 이 기능이 더 이상 유지되지 않습니다. 이 경우에는 쿼리에 따라 달라지므로 관련된 경우 프로파일을 작성해야 합니다.관련 SO 질문으로는 하나의 쿼리와 많은 작은 쿼리 무엇이 더 빠릅니까?


으로, 를 이 더 수 있습니다.TRUNCATEDROP TABLE특별한 이유가 없다면요

self.cursor.execute(
    f'CREATE TABLE IF NOT EXISTS {table_name};'
    'SET FOREIGN_KEY_CHECKS=0;'
    f'TRUNCATE TABLE {table_name};'
    'SET FOREIGN_KEY_CHECKS=1;'
    f'INSERT INTO {table_name} SELECT * FROM mytable;'
)

저는 프로젝트에서 이런 유형의 문제에 여러 번 부딪혔습니다.많은 연구 끝에 몇 가지 점과 제안을 찾았습니다.

  1. execute()메서드는 한 번에 하나의 쿼리에 대해 잘 작동합니다.왜냐하면 실행 방법은 상태를 관리하기 때문입니다.

알고있어요cursor.execute(operation, params=None, multi=True)여러 가지 질문을 받다그러나 이 경우 매개 변수가 제대로 작동하지 않으며 내부 오류 예외로 인해 모든 결과가 손상되는 경우도 있습니다.그리고 코드는 방대하고 모호해집니다.심지어 의사들도 이것을 언급합니다.

  1. executemany(operation, seq_of_params)매번 실행하는 것은 좋은 방법이 아닙니다.하나 이상의 결과 집합을 생성하는 연산은 정의되지 않은 동작을 구성하며, 구현은 연산의 호출로 결과 집합이 생성되었음을 감지할 때 예외를 발생시키는 것이 허용(필요하지는 않음)되기 때문입니다.[소스 - 문서]

제안 1-:

다음과 같은 쿼리 목록을 만듭니다.

table_name = 'test'
quries = [
          'SET FOREIGN_KEY_CHECKS=0;',
          'DROP TABLE IF EXISTS {};'.format(table_name),
          'SET FOREIGN_KEY_CHECKS=1;',
          'CREATE TABLE {} select * from mytable;'.format(table_name),
         ]
for query in quries:
    result = self.cursor.execute(query)
    # Do operation with result

제안 2-:

구술로 설정합니다.[you can also make this by executemany for recursive parameters for some special cases.]

quries = [
          {'DROP TABLE IF EXISTS %(table_name);':{'table_name': 'student'}},
          {'CREATE TABLE %(table_name) select * from mytable;': 
           {'table_name':'teacher'}},
          {'SET FOREIGN_KEY_CHECKS=0;': ''}
         ]
for data in quries:
    for query, parameter in data.iteritems():
        if parameter == '':
            result = self.cursor.execute(query)
            # Do something with result
        else:
            result = self.cursor.execute(query, parameter)
            # Do something with result

스크립트와 함께 split을 사용할 수도 있습니다.Not recommended

with connection.cursor() as cursor:
    for statement in script.split(';'):
        if len(statement) > 0:
             cursor.execute(statement + ';')

-: -: 합니다를 합니다.list of query하지만 어떤 하기를 .dictionary접근.

MySQL Cursor에 대한 설명서를 봅니다.실행에 옮기다

당신이 그 안에서 통과할 수 있다고 주장합니다.multi하나의 문자열에서 여러 개의 쿼리를 실행할 수 있는 매개 변수입니다.

multi를 True로 설정하면 execute()는 연산 문자열에 지정된 여러 문을 실행할 수 있습니다.

multi두(선택 행()입니다입니다.


operation = 'SELECT 1; INSERT INTO t1 VALUES (); SELECT 2'
for result in cursor.execute(operation, multi=True):

와 함께import mysql.connector

당신은 명령을 따를 수 있습니다. 단지 t1과 에피소드를 당신만의 tabaes로 바꾸기만 하면 됩니다.

tablename= "t1"
 mycursor.execute("SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS {}; SET FOREIGN_KEY_CHECKS=1;CREATE TABLE {} select * from episodes;".format(tablename, tablename),multi=True)

이 작업이 실행되는 동안 활성화한 후 적용될 외래 키 구속 장치가 문제를 일으키지 않도록 해야 합니다.

테이블 이름이 사용자가 입력할 수 있는 항목인 경우 테이블 이름의 화이트리스트를 고려해야 합니다.

준비된 문은 테이블 및 열 이름과 함께 작동하지 않으므로 올바른 위치에서 올바른 테이블 이름을 얻기 위해 문자열 교체를 사용해야 합니다. 이는 코드를 sql 주입취약하게 만듭니다.

multi=True커넥터에서 4개의 명령어를 실행하기 위해 필요한데, 테스트해보니 디버거에서 요구했습니다.

  1. executivecript() 여러 SQL 문을 한 번에 실행할 수 있는 편리한 방법입니다.파라미터로 받는 SQL 스크립트를 실행합니다.구문:

    sqlite3.connect.executescript(script)

예제 코드:

import sqlite3 

# Connection with the DataBase 
# 'library.db' 
connection = sqlite3.connect("library.db") 
cursor = connection.cursor() 

# SQL piece of code Executed 
# SQL piece of code Executed 
cursor.executescript(""" 
    CREATE TABLE people( 
        firstname, 
        lastname, 
        age 
    ); 

    CREATE TABLE book( 
        title, 
        author, 
        published 
    ); 

    INSERT INTO 
    book(title, author, published) 
    VALUES ( 
        'Dan Clarke''s GFG Detective Agency', 
        'Sean Simpsons', 
        1987 
    ); 
    """) 

sql = """ 
SELECT COUNT(*) FROM book;"""

cursor.execute(sql) 

# The output in fetched and returned 
# as a List by fetchall() 
result = cursor.fetchall() 
print(result) 

sql = """ 
SELECT * FROM book;"""

cursor.execute(sql) 

result = cursor.fetchall() 
print(result) 

# Changes saved into database 
connection.commit() 

# Connection closed(broken) 
# with DataBase 
connection.close() 

출력:

[(1,)] [('댄 클라크의 GFG 탐정단', 'Sean Simpsons', 1987)]

  1. executive many() 데이터 파일에서 데이터베이스에 대량의 데이터를 삽입해야 하는 경우가 많습니다(간단히 사례를 들어 목록, 배열).매번 한 줄씩 데이터베이스에 기록하는 것보다 코드를 여러 번 반복하는 것이 간단합니다.그러나 이 경우 루프를 사용하는 것은 적합하지 않을 것이며, 아래의 예는 그 이유를 보여줍니다.executemany()의 구문 및 사용법은 아래와 같이 설명되며 루프처럼 사용될 수 있는 방법은 다음과 같습니다.

출처: GeeksForGeeks: SQL Using Python 이 출처 확인..이것은 당신에게 좋은 것들을 많이 가지고 있습니다.

과 로 closing상황 관리자.

from contextlib import closing
from typing import List

import mysql.connector
import logging

logger = logging.getLogger(__name__)


def execute(stmts: List[str]) -> None:
    logger.info("Starting daily execution")

    with closing(mysql.connector.connect()) as connection:
        try:
            with closing(connection.cursor()) as cursor:
                cursor.execute(' ; '.join(stmts), multi=True)
        except Exception:
            logger.exception("Rollbacking changes")
            connection.rollback()
            raise
        else:
            logger.info("Finished successfully")

연결이나 커서가 잘못 연결된 것이 아니라면 현재 보유 중인 mysql 드라이버 버전에 따라 컨텍스트 관리자가 아닐 수 있으므로 이는 pythonic 안전 솔루션입니다.

언급URL : https://stackoverflow.com/questions/62584640/suggested-way-to-run-multiple-sql-statements-in-python