क्लाज में एक python MySQLDB IN में उपयोग के लिए एक सूची को निहित करना


84

मुझे पता है कि स्ट्रिंग में सूची कैसे मैप करें:

foostring = ",".join( map(str, list_of_ids) )

और मुझे पता है कि मैं उस स्ट्रिंग को एक इन क्लॉज में प्राप्त करने के लिए निम्नलिखित का उपयोग कर सकता हूं:

cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))

MySQLDB का उपयोग करके SAFELY (SQL इंजेक्शन से बचना) एक ही चीज़ को पूरा करने के लिए मुझे जो चाहिए वह है। उपर्युक्त उदाहरण में क्योंकि फ़ॉस्ट्रिंग को निष्पादित करने के तर्क के रूप में पारित नहीं किया गया है, यह कमजोर है। मुझे भी mysql लाइब्रेरी के बाहर बोली और बचना होगा।

( संबंधित एसओ प्रश्न है , लेकिन वहां सूचीबद्ध उत्तर या तो MySQLDB के लिए काम नहीं करते हैं या SQL इंजेक्शन के लिए असुरक्षित हैं।)


आप इसी तरह के एक प्रश्न से कुछ प्रेरणा प्राप्त करने में सक्षम हो सकते हैं जो php stackoverflow.com/questions/327274/…
Zoredache


@mluebke क्वेरी में कई सूचियाँ पास करने के बारे में कोई विचार?
दीपन डेडानिया

जवाबों:


157

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

इस तरह आप अपने आप को उद्धृत करने से बचते हैं, और सभी प्रकार के एसक्यूएल इंजेक्शन से बचते हैं।

ध्यान दें कि डेटा ( list_of_ids) सीधे mysql के ड्राइवर पर जा रहा है, एक पैरामीटर के रूप में (क्वेरी टेक्स्ट में नहीं) ताकि कोई इंजेक्शन न हो। आप स्ट्रिंग में अपनी इच्छानुसार कोई भी चार्ट छोड़ सकते हैं, चार्ट को हटाने या उद्धरण करने की आवश्यकता नहीं है।


2
@heikogerlach: मैं% s को उद्धृत नहीं कर रहा हूँ ... पहली पंक्ति "% s,% s,% s" की एक स्ट्रिंग बनाती है ... list_of_ids लंबाई का समान आकार।
nosklo

अर्घ, आप सही कह रहे हैं। सख्त दिखने की जरूरत है। किसी तरह मैंने इसे मिलाया। अच्छा समाधान, हालांकि।

क्या यह काम sqlite में भी होगा? क्योंकि मैंने अभी इसकी कोशिश की थी और यह सिंटैक्स त्रुटियों को इंगित करता है।
सोहैब

@ शोहेत इन द स्काईलाइट इन द रिप्लेसमेंट चार इसलिए ऐसा ?नहीं %sहै कि अगर आप पहली लाइन को बदलेंगे तो यह काम करेगा format_strings = ','.join('?' * len(list_of_ids))
nosklo

1
@kdas आपके मामले में आप अपने क्वेरी में % format_stringsअन्य %sप्लेसहोल्डर्स को बदलने का हिस्सा नहीं चाहते हैं , केवल IN (%s)प्लेसहोल्डर - इसे प्राप्त करने का तरीका यह है %कि आप जिस जगह को बदलना चाहते हैं उसे छोड़कर सभी query = ("select distinct cln from vcf_commits where branch like %%s and repository like %%s and filename in (%s) and author not like %%s" % format_strings,); cursor.execute(query, (branch, repository) + tuple(fname_list) + (invalid_author,))
चार्ट को दोगुना करें

5

हालांकि यह सवाल काफी पुराना है, लेकिन यह सोचा कि अगर मैं चाहता था तो किसी और की प्रतिक्रिया को छोड़ना बेहतर होगा

स्वीकार किए गए उत्तर गड़बड़ हो जाता है जब हमारे पास बहुत सारे परमेस होते हैं या यदि हम नामित मापदंडों का उपयोग करना चाहते हैं

कुछ परीक्षणों के बाद

ids = [5, 3, ...]  # list of ids
cursor.execute('''
SELECT 
...
WHERE
  id IN %(ids)s
  AND created_at > %(start_dt)s
''', {
  'ids': tuple(ids), 'start_dt': '2019-10-31 00:00:00'
})

के साथ परीक्षण किया गया python2.7,pymysql==0.7.11


2
यह अजगर 3 और mysql-कनेक्टर-पायथन 8.0.21 के साथ काम नहीं करता है। "Python tuple को MySQL प्रकार में परिवर्तित नहीं किया जा सकता" एक त्रुटि दी गई है।
Rubms

-1

यदि आप उपयोग करते हैं Django 2.0 or 2.1और Python 3.6, यह सही तरीका है:

from django.db import connection
RESULT_COLS = ['col1', 'col2', 'col3']
RESULT_COLS_STR = ', '.join(['a.'+'`'+i+'`' for i in RESULT_COLS])
QUERY_INDEX = RESULT_COLS[0]

TABLE_NAME = 'test'
search_value = ['ab', 'cd', 'ef']  # <-- a list
query = (
    f'SELECT DISTINCT {RESULT_COLS_STR} FROM {TABLE_NAME} a '
    f'WHERE a.`{RESULT_COLS[0]}` IN %s '
    f'ORDER BY a.`{RESULT_COLS[0]}`;'
)  # <- 'SELECT DISTINCT a.`col1`, a.`col2`, a.`col3` FROM test a WHERE a.`col1` IN %s ORDER BY a.`col1`;'
with connection.cursor() as cursor:
    cursor.execute(query, params=[search_value])  # params is a list with a list as its element

रेफरी: https://stackoverflow.com/a/23891759/2803344 https://docs.djangoproject.com/en/2.1/topics/db/sql/#passing-parameters-into-raw


-1

हालांकि यह सवाल काफी पुराना है। मैं अपना समाधान साझा कर रहा हूं अगर यह किसी की मदद कर सकता है।

list_to_check = ['A', 'B'] cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])

के साथ परीक्षण किया गया Python=3.6


मुझे डर है कि यह समाधान SQL इंजेक्शन के हमलों के लिए असुरक्षित है, क्योंकि list_to_checkएसक्यूएल-बच नहीं रहा है। यही कारण है कि मानों को मापदंडों के रूप में पारित करना executeअधिक उपयुक्त है। इस समाधान का उपयोग बहुत सावधानी से करें (अर्थात, इनपुट आईडी आपके एप्लिकेशन के बाहर से पैरामीटर के रूप में प्राप्त नहीं होती हैं), क्योंकि कोई व्यक्ति आपके सिस्टम पर हमला करने और आपके डेटाबेस तक पहुंचने के लिए इसका उपयोग कर सकता है।
Rubms

-2

सूची बोध का उपयोग करते हुए एक और सरल उपाय:

# creating a new list of strings and convert to tuple
sql_list = tuple([ key.encode("UTF-8") for key in list_of_ids ])

# replace "{}" with "('id1','id2',...'idlast')"
cursor.execute("DELETE FROM foo.bar WHERE baz IN {}".format(sql_list))

-4
list_of_ids = [ 1, 2, 3]
query = "select * from table where x in %s" % str(tuple(list_of_ids))
print query

यह कुछ उपयोग-मामलों के लिए काम कर सकता है यदि आप उस विधि से चिंतित नहीं होना चाहते हैं जिसमें आपको क्वेरी स्ट्रिंग को पूरा करने के लिए तर्क पारित करना होगा और बस आमंत्रित करना चाहते हैं cursror.execute(query)

एक और तरीका हो सकता है:

"select * from table where x in (%s)" % ', '.join(str(id) for id in list_of_ids)

-7

बहुत सरल: बस नीचे के गठन का उपयोग करें

rules_id = ["9", "10"]

sql1 = "अटेंडेंस * फ्रॉम अटेंडेंस_रुल्स_स्टाफ आइडी इन (" + ","। जॉइन (मैप (str, रूल्स_ड)) + ")"

","। जॉइन (नक्शा (str, rules_id))


यह एसक्यूएल उद्धृत कहां करता है और क्या यह बाइंड चर के बजाय शाब्दिक का उपयोग नहीं करता है?
8

जरूरत नहीं है, यह बस ठीक काम कर रहा है। आप परीक्षण कर सकते हैं क्योंकि टुपल गठन सीधे पहले ब्रेसिज़ ("9", "10") के साथ स्ट्रिंग के रूप में परिवर्तित हो जाता है। जो कि एसक्यूएल गठन को समायोजित करते हैं। तो तुम बनाने के लिए अन्य गठन की जरूरत नहीं है एसक्यूएल adjastable है
मिज़ानूर रहमान

1
और अगर एक rules_idहोता है "); DROP TABLES Bobby --?
ग्रहण करता है

पहले से ही "एक सूची को" नहीं "निहित करना बताया गया है ... तो क्वेरी से पहले आपको मान्य करने की आवश्यकता है
मिज़ानुर रहमान

या उपयोग करें: sql1 = "अटेंडेंस * फ्रॉम अटेंडेंस_रुल्स_स्टाफ व्हेयर आईडी इन (" "", "। जॉइन (मैप (str, रूल्स_ड)) +")
रहमान 3
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.