programing

SELECT 실행 중...위치..."MySQLdb를 사용하여 입력..."

minecode 2022. 10. 11. 21:30
반응형

SELECT 실행 중...위치..."MySQLdb를 사용하여 입력..."

Python에서 일부 SQL을 실행하는 데 문제가 있습니다. 비슷한 SQL이 정상적으로 동작하는데도 불구하고mysql커맨드 라인

표는 다음과 같습니다.

mysql> SELECT * FROM foo;
+-------+-----+
| fooid | bar |
+-------+-----+
|     1 | A   | 
|     2 | B   | 
|     3 | C   | 
|     4 | D   | 
+-------+-----+
4 rows in set (0.00 sec)

mysql 명령줄에서 다음 SQL 쿼리를 문제없이 실행할 수 있습니다.

mysql> SELECT fooid FROM foo WHERE bar IN ('A','C');
SELECT fooid FROM foo WHERE bar IN ('A','C');
+-------+
| fooid |
+-------+
|     1 | 
|     3 | 
+-------+
2 rows in set (0.00 sec)

그러나 Python 내에서 같은 작업을 하려고 하면 2개의 행을 예상한 반면 행이 표시되지 않습니다.

import MySQLdb
import config
connection=MySQLdb.connect(
    host=config.HOST,user=config.USER,passwd=config.PASS,db='test')
cursor=connection.cursor()

sql='SELECT fooid FROM foo WHERE bar IN %s'
args=[['A','C']]
cursor.execute(sql,args)
data=cursor.fetchall()
print(data)
# ()

그래서 질문은: python 코드를 어떻게 수정해야 그것들을 선택할 수 있는가이다.fooid이 장소bar('A','C')?

그나저나, 만약 내가 그 역할을 바꾼다면bar그리고.fooid, 나는 그것들을 선택하기 위한 코드를 얻을 수 있다.bar이 장소fooid(1,3)성공했습니다.이러한 쿼리(아래)는 동작하고, 다른 쿼리(위)는 동작하지 않는 이유를 이해할 수 없습니다.

sql='SELECT bar FROM foo WHERE fooid IN %s'
args=[[1,3]]
cursor.execute(sql,args)
data=cursor.fetchall()
print(data)
# (('A',), ('C',))

그리고 확실히 말씀드리자면, 이게 바로 어떻게 하면foo테이블이 작성되었습니다.

mysql> DROP TABLE IF EXISTS foo;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE `foo` (
          `fooid` int(11) NOT NULL AUTO_INCREMENT,
          `bar` varchar(10) NOT NULL,
          PRIMARY KEY (`fooid`));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT into foo (bar) values ('A'),('B'),('C'),('D');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

편집: 일반 쿼리 로그를 활성화하면mysqld -l /tmp/myquery.log그렇군요.

mysqld, Version: 5.1.37-1ubuntu5.5-log ((Ubuntu)). started with:
Tcp port: 3306  Unix socket: /var/run/mysqld/mysqld.sock
Time                 Id Command    Argument
110101 11:45:41     1 Connect   unutbu@localhost on test
            1 Query set autocommit=0
            1 Query SELECT fooid FROM foo WHERE bar IN ("'A'", "'C'")
            1 Query SELECT bar FROM foo WHERE fooid IN ('1', '3')
            1 Quit

실제로, 너무 많은 견적이 주위에 배치되어 있는 것 같습니다.A그리고.C.

@Amber님의 코멘트 덕분에 무엇이 잘못되고 있는지 더 잘 알 수 있었습니다.MySQLdb는 매개 변수화된 인수를 변환합니다.['A','C']로.("'A'","'C'").

를 사용하여 파라미터화된 쿼리를 만드는 방법이 있습니까?INSQL 구문?아니면 SQL 문자열을 수동으로 구성해야 합니까?

유감스럽게도 쿼리 파라미터를 수동으로 작성해야 합니다.왜냐하면 제가 알기론 빌트인은 없습니다.bind결속법list에 대해서IN휴지기와 유사한 절setParameterList()단, 다음과 같은 방법으로 동일한 작업을 수행할 수 있습니다.

Python 3:

args=['A', 'C']
sql='SELECT fooid FROM foo WHERE bar IN (%s)' 
in_p=', '.join(list(map(lambda x: '%s', args)))
sql = sql % in_p
cursor.execute(sql, args)

Python 2:

args=['A', 'C']
sql='SELECT fooid FROM foo WHERE bar IN (%s)' 
in_p=', '.join(map(lambda x: '%s', args))
sql = sql % in_p
cursor.execute(sql, args)

SQL에서 %s 문자열 목록을 작성하는 데 더 효율적이라고 생각하는 유사한 솔루션을 다음에 제시하겠습니다.

를 사용합니다.list_of_ids직접:

format_strings = ','.join(['%s'] * len(list_of_ids))
cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings,
                tuple(list_of_ids))

이렇게 하면 자신의 견적을 낼 필요가 없어지고 모든 종류의 SQL 주입을 피할 수 있습니다.

데이터(list_of_ids(쿼리 텍스트가 아닌) 파라미터로서 mysql의 드라이버로 직접 이동하기 때문에 주입은 없습니다.문자열에 원하는 문자를 남길 수 있습니다.문자를 삭제하거나 따옴표로 묶을 필요는 없습니다.

쿼리에 IN 목록 이외의 다른 파라미터가 있는 경우 JG의 응답에 대한 다음 확장자가 도움이 될 수 있습니다.

ids = [1, 5, 7, 213]
sql = "select * from person where type=%s and id in (%s)"
in_ids = ', '.join(map(lambda x: '%s', ids))
sql = sql % ('%s', in_ids)
params = []
params.append(type)
params.extend(ids)
cursor.execute(sql, tuple(params))

즉, 선형 배열의 모든 매개 변수를 조인한 다음 실행 메서드에 태플로 전달합니다.

이거면 돼요.

myTuple= tuple(myList)
sql="select fooid from foo where bar in "+str(myTuple)
cursor.execute(sql)

주앙이 제안한 것을 할 수 있는 기능을 만들 수 있지 않을까?예를 들어 다음과 같습니다.

def cursor_exec(cursor, query, params):
    expansion_params= []
    real_params = []
    for p in params:
       if isinstance(p, (tuple, list)):
         real_params.extend(p)
         expansion_params.append( ("%s,"*len(p))[:-1] )
       else:
         real_params.append(p)
         expansion_params.append("%s")
    real_query = query % expansion_params
    cursor.execute(real_query, real_params)

Tornado의 mysql 래퍼와 함께 IN 목록 쿼리를 사용하기 위해 Joang의 솔루션에서 모든 변형을 시도했지만 여전히 "TypeError: not enough arguments for format string" 오류가 발생하고 있습니다.목록 var "*args"에 "*"를 추가하면 효과가 있었습니다.

args=['A', 'C']
sql='SELECT fooid FROM foo WHERE bar IN (%s)'
in_p=', '.join(list(map(lambda x: '%s', args)))
sql = sql % in_p
db.query(sql, *args)

Jooo와 satru의 코드를 개선하여 중첩된 반복가능성을 받아들여 올바르게 처리하는 실행으로 커서 작성에 사용할 수 있는 커서 믹스인을 만들 것을 제안합니다.더 、 름 、 이 、 은 、 。경우 Python3을 합니다.strbasestring.

from MySQLdb.cursors import Cursor

class BetterExecuteMixin(object):
    """
    This mixin class provides an implementation of the execute method
    that properly handles sequence arguments for use with IN tests.
    Examples:
    execute('SELECT * FROM foo WHERE id IN (%s) AND type=%s', ([1,2,3], 'bar'))
    # Notice that when the sequence is the only argument, you still need
    # a surrounding tuple:
    execute('SELECT * FROM foo WHERE id IN (%s)', ([1,2,3],))
    """

    def execute(self, query, args=None):
        if args is not None:
            try:
                iter(args)
            except TypeError:
                args = (args,)
            else:
                if isinstance(args, basestring):
                    args = (args,)
            real_params = []
            placeholders = []
            for arg in args:
                # sequences that we treat as a single argument
                if isinstance(arg, basestring):
                    real_params.append(arg)
                    placeholders.append('%s')
                    continue
                try:
                    real_params.extend(arg)
                    placeholders.append(','.join(['%s']*len(arg)))
                except TypeError:
                    real_params.append(arg)
                    placeholders.append('%s')
            args = real_params
            query = query % tuple(placeholders)
        return super(BetterExecuteMixin, self).execute(query, args)

class BetterCursor(BetterExecuteMixin, Cursor):
    pass

그 후 다음과 같이 사용할 수 있습니다(역호환도 가능합니다).

import MySQLdb
conn = MySQLdb.connect(user='user', passwd='pass', db='dbname', host='host',
                       cursorclass=BetterCursor)
cursor = conn.cursor()
cursor.execute('SELECT * FROM foo WHERE id IN (%s) AND type=%s', ([1,2,3], 'bar'))
cursor.execute('SELECT * FROM foo WHERE id IN (%s)', ([1,2,3],))
cursor.execute('SELECT * FROM foo WHERE type IN (%s)', (['bar', 'moo'],))
cursor.execute('SELECT * FROM foo WHERE type=%s', 'bar')
cursor.execute('SELECT * FROM foo WHERE type=%s', ('bar',))

매우 심플:

아래 포메이션 ###을 사용합니다.

rules_id = ["9","10"]

sql2 = "SELECT * FROM attendance_rules_staff WHERE id in"+str(tuple(rules_id))

str(tuple(rules_id)).

왜 이런 경우엔 이것만 안 되는 거죠?

args = ['A', 'C']
sql = 'SELECT fooid FROM foo WHERE bar IN (%s)' 
in_p  =', '.join(list(map(lambda arg:  "'%s'" % arg, args)))
sql = sql % in_p
cursor.execute(sql)

결과는 다음과 같습니다.

SELECT fooid FROM foo WHERE bar IN ('A', 'C')

args는 태플이어야 합니다.

예:

args = ('A','B')

args = ('A',) # in case of single

언급URL : https://stackoverflow.com/questions/4574609/executing-select-where-in-using-mysqldb

반응형