पैरामीटर के रूप में sql क्वेरी में अजगर सूची


124

मेरे पास एक अजगर की सूची है, मैं कहता हूं कि एल

l = [1,5,8]

मैं सूची के सभी तत्वों के लिए डेटा प्राप्त करने के लिए एक sql क्वेरी लिखना चाहता हूं, कहते हैं

select name from students where id = |IN THE LIST l|

मैं इसे कैसे पूर्ण करूं?

जवाबों:


111

अब तक के उत्तर एक सादा SQL स्ट्रिंग में मानों को गतिमान कर रहे हैं। पूर्णांक के लिए यह बिल्कुल ठीक है, लेकिन अगर हम इसे स्ट्रिंग्स के लिए करना चाहते थे तो हमें भागने का मुद्दा मिलता है।

यहाँ एक पैरामीटर है जो एक पैरामीटर क्वेरी का उपयोग करता है जो दोनों के लिए काम करेगा:

placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)

11
','.join(placeholder * len(l))थोड़ा कम होगा जबकि अभी भी पठनीय imho
ThiefMaster

7
@ थिम्समास्टर: हां, ([placeholder]*len(l))सामान्य मामले में होना चाहिए क्योंकि प्लेसहोल्डर कई अक्षर हो सकते हैं।
bobince

1
@bobince मेरे मामले में मैंने एक वेरिएबल a = 'जॉन' और b = 'स्नो' को असाइन किया है और इसे एक ट्यूपल में संग्रहीत किया है, जिसका नाम = ['a, b'] है और उसी क्वेरी को किया। ऐसा करने से मुझे एरोब यानी टाइप एरर मिला: स्ट्रिंग फॉर्मेटिंग के दौरान सभी तर्क परिवर्तित नहीं हुए। मैं इसे कैसे सुलझाऊंगा
TechJhola

2
आप इस काम को छोड़ने के बजाय "हाथ से" क्यों जुड़ना चाहते हैं? कुंजी एक सूची के बजाय टपल का उपयोग करना है ...
एलेसेंड्रो डेंटेला

5
इस उत्तर के आधार पर यहां पायथन 3.6 के लिए एक एकल लाइन समाधान है cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l)। @bobince, आपको अपने समाधान में यह भी टिप्पणी करनी चाहिए कि ?एसक्यूएल इंजेक्शन से बचने के लिए उपयोग करना सुरक्षित तरीका है। यहाँ बहुत सारे उत्तर हैं जो कमजोर हैं, मूल रूप से कोई भी जो अजगर में तार लगाता है।
टोटो_टिको

59

सबसे आसान तरीका सूची को tupleपहले की ओर मोड़ना है

t = tuple(l)
query = "select name from studens where id IN {}".format(t)

1
यह वास्तव में सही उत्तर है। मुझे यकीन नहीं है कि इसे नजरअंदाज क्यों किया गया। पहले आप सूची l सेट करें, फिर tuple का उपयोग करें, फिर tuple को क्वेरी में पास करें। बहुत बढ़िया।
MEdwin

11
जैसा कि @renstrm द्वारा कहा गया है, यह काम नहीं करता है यदि l में केवल एक तत्व है, तो आप id IN (1,) को समाप्त करेंगे। जो एक वाक्य रचना त्रुटि है।
डबलडाउन

1
@Boris यदि आप गारंटी नहीं दे सकते कि आपके इनपुट हमेशा एक सूची है, तो आप इस एक लाइनर के समान कुछ कर सकते हैं stackoverflow.com/questions/38821586/... आपकी क्वेरी के लिए तर्क पार करने से पहले
आमिर Imani

10
यह स्वीकार किए गए के अलावा अन्य उत्तरों की तरह, SQL इंजेक्शन के लिए असुरक्षित है और इसका उपयोग नहीं किया जाना चाहिए।
बेकन बिट्स

2
@BaconBits निष्पक्ष चेतावनी, लेकिन कुछ अनुप्रयोगों के लिए जहां SQL इंजेक्शन एक मुद्दा नहीं है (उदाहरण के लिए, एक डेटाबेस का विश्लेषण जहां मैं केवल उपयोगकर्ता हूं), यह करेगा।
इरिन

26

इसे जटिल मत करो, इस के लिए समाधान सरल है।

l = [1,5,8]

l = tuple(l)

params = {'l': l}

cursor.execute('SELECT * FROM table where id in %(l)s',params)

यहाँ छवि विवरण दर्ज करें

मुझे उम्मीद है कि इससे मदद मिली !!!


10
यह काम नहीं करता है अगर lसिर्फ एक तत्व होता है, तो आप समाप्त करेंगे id IN (1,)। जो एक वाक्य रचना त्रुटि है।
वृक्क

3
यदि l में केवल 1 तत्व है, तो सुनिश्चित करें कि यह एक टपल है और यह काम करेगा। यह समाधान स्वीकृत की तुलना में मेरी राय में स्पष्ट है।
एलेसैंड्रो डेंटेला

2
लेकिन यह अभी भी काम नहीं करेगा अगर ट्यूपल खाली है, इसलिए क्वेरी निष्पादन से पहले अतिरिक्त जांच होनी चाहिए।
Никита Конин

2
यह मेरे साथ काम नहीं करता है sqlite3। आपने किस पुस्तकालय के खिलाफ यह परीक्षण किया?
निक चामास

1
अच्छा समाधान है लेकिन @renstrm और Никита-Конин के लिए अतिरिक्त जांच की आवश्यकता होती है जब टपल में एक भी तत्व या कोई तत्व नहीं होता है।
अनीश सना

23

आप जो SQL चाहते है

select name from studens where id in (1, 5, 8)

यदि आप इसका उपयोग उस अजगर से करना चाहते हैं जिसका आप उपयोग कर सकते हैं

l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'

नक्शा समारोह तार का उपयोग कर अल्पविराम के द्वारा एक साथ चिपके किया जा सकता है की एक सूची में सूची बदल str.join विधि।

वैकल्पिक रूप से:

l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join((str(n) for n in l)) + ')'

यदि आप नक्शे समारोह के लिए जनरेटर अभिव्यक्ति पसंद करते हैं ।

अद्यतन: एस। टिप्पणियों में उल्लेख किया गया है कि पायथन SQLite बाइंडिंग अनुक्रमों का समर्थन नहीं करते हैं। उस मामले में, आप चाहते हो सकता है

select name from studens where id = 1 or id = 5 or id = 8

द्वारा उत्पन्न

sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))

2
:-( पायथन SQLite बाइंडिंग दृश्यों का समर्थन नहीं करता है।
S.Lott

ओह? मुझे एहसास नहीं हुआ। तो फिर, मुझे एहसास नहीं था कि हम एक SQLite बाध्यकारी समाधान के लिए जा रहे थे।
ब्लेयर कॉनराड

क्षमा करें, SQLite का सुझाव देना या लागू नहीं करना - सिर्फ दुख की बात है कि सूचियों के लिए बाइंडिंग वहाँ काम नहीं करती है।
S.Lott

11

string.join सूची मानों को अल्पविराम द्वारा अलग किया जाता है, और क्वेरी स्ट्रिंग बनाने के लिए प्रारूप ऑपरेटर का उपयोग करें ।

myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))

( साभार , ब्लेयर-कॉनराड )


2
चूंकि यह दृष्टिकोण डेटाबेस पैरामीटर प्रतिस्थापन का उपयोग नहीं करता है, यह आपको SQL इंजेक्शन हमलों के लिए उजागर करता है। %यहां इस्तेमाल किया जा रहा है स्वरूपण सादे पायथन स्ट्रिंग है।
निक चामास

8

मुझे बोबिन्स का उत्तर पसंद है:

placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)

लेकिन मैंने इस पर ध्यान दिया:

placeholders= ', '.join(placeholder for unused in l)

के साथ प्रतिस्थापित किया जा सकता है:

placeholders= ', '.join(placeholder*len(l))

मुझे यह अधिक प्रत्यक्ष लगता है यदि कम चतुर और कम सामान्य। यहाँ lएक लंबाई होना आवश्यक है (अर्थात एक __len__विधि को परिभाषित करता है जो एक विधि को परिभाषित करता है ), जो एक समस्या नहीं होनी चाहिए। लेकिन प्लेसहोल्डर भी एक ही चरित्र का होना चाहिए। बहु-चरित्र प्लेसहोल्डर उपयोग का समर्थन करने के लिए:

placeholders= ', '.join([placeholder]*len(l))

2

@Umounted उत्तर के लिए समाधान, क्योंकि वह एक-तत्व के साथ टूट गया था, चूंकि (1,) मान्य SQL नहीं है ।:

>>> random_ids = [1234,123,54,56,57,58,78,91]
>>> cursor.execute("create table test (id)")
>>> for item in random_ids:
    cursor.execute("insert into test values (%d)" % item)
>>> sublist = [56,57,58]
>>> cursor.execute("select id from test where id in %s" % str(tuple(sublist)).replace(',)',')'))
>>> a = cursor.fetchall()
>>> a
[(56,), (57,), (58,)]

Sql स्ट्रिंग के लिए अन्य समाधान:

cursor.execute("select id from test where id in (%s)" % ('"'+'", "'.join(l)+'"'))

5
एसक्यूएल इंजेक्शन की वजह से यह बेहतर समाधान नहीं है।
अनुराग

2
placeholders= ', '.join("'{"+str(i)+"}'" for i in range(len(l)))
query="select name from students where id (%s)"%placeholders
query=query.format(*l)
cursor.execute(query)

इससे आपकी समस्या का समाधान हो जाना चाहिए।


2

यदि आप Psycopg2 लाइब्रेरी के साथ PostgreSQL का उपयोग कर रहे हैं, तो आप अपने टुपल अनुकूलन को आपके लिए सभी भागने और स्ट्रिंग प्रक्षेप करने दे सकते हैं, जैसे:

ids = [1,2,3]
cur.execute(
  "SELECT * FROM foo WHERE id IN %s",
  [tuple(ids)])

यानी यह सुनिश्चित करें कि आप INपैरामीटर को एक के रूप में पारित कर रहे हैं tuple। यदि यह है तो listआप एक = ANYसरणी सिंटैक्स का उपयोग कर सकते हैं :

cur.execute(
  "SELECT * FROM foo WHERE id = ANY (%s)",
  [list(ids)])

ध्यान दें कि इन दोनों को एक ही क्वेरी प्लान में बदल दिया जाएगा ताकि आपको बस जो भी आसान हो उसका उपयोग करना चाहिए। जैसे अगर आपकी सूची टपल में आती है तो पूर्व का उपयोग करें, यदि वे सूची में संग्रहीत हैं तो बाद का उपयोग करें।


1

उदाहरण के लिए, यदि आप वर्ग क्वेरी चाहते हैं:

select name from studens where id in (1, 5, 8)

व्हाट अबाउट:

my_list = [1, 5, 8]
cur.execute("select name from studens where id in %s" % repr(my_list).replace('[','(').replace(']',')') )


1
l = [1] # or [1,2,3]

query = "SELECT * FROM table WHERE id IN :l"
params = {'l' : tuple(l)}
cursor.execute(query, params)

:varअंकन सरल लगता है। (पायथन 3.7)


0

यह पैरामीटर प्रतिस्थापन का उपयोग करता है और एकल मूल्य सूची मामले की देखभाल करता है:

l = [1,5,8]

get_operator = lambda x: '=' if len(x) == 1 else 'IN'
get_value = lambda x: int(x[0]) if len(x) == 1 else x

query = 'SELECT * FROM table where id ' + get_operator(l) + ' %s'

cursor.execute(query, (get_value(l),))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.