पायथन एसक्यूएल क्वेरी स्ट्रिंग प्रारूपण


93

मैं एक sql क्वेरी स्ट्रिंग को प्रारूपित करने का सबसे अच्छा तरीका खोजने की कोशिश कर रहा हूँ। जब मैं अपना एप्लिकेशन डीबग कर रहा हूं, तो मैं सभी sql क्वेरी स्ट्रिंग्स को दर्ज करने के लिए लॉग इन करना चाहूंगा, और यह महत्वपूर्ण है कि स्ट्रिंग ठीक से तैयार की गई हो।

विकल्प 1

def myquery():
    sql = "select field1, field2, field3, field4 from table where condition1=1 and condition2=2"
    con = mymodule.get_connection()
    ...
  • यह sql string को प्रिंट करने के लिए अच्छा है।
  • यह एक अच्छा समाधान नहीं है यदि स्ट्रिंग लंबी है और 80 वर्णों की मानक चौड़ाई के अनुरूप नहीं है।

विकल्प 2

def query():
    sql = """
        select field1, field2, field3, field4
        from table
        where condition1=1
        and condition2=2"""
    con = mymodule.get_connection()
    ...
  • यहां कोड स्पष्ट है लेकिन जब आप sql क्वेरी स्ट्रिंग प्रिंट करते हैं तो आपको ये सभी कष्टप्रद सफेद स्थान मिलते हैं।

    u '\ nselect फ़ील्ड 1, फ़ील्ड 2, फ़ील्ड 3, फ़ील्ड 4 \ n_ _ ___ टेबल से \ n _ ___ जहां condition1 = 1 \ n _ ___ _and condition2 = 2'

नोट: मैंने अंडरस्कोर के साथ सफेद रिक्त स्थान को बदल दिया है _, क्योंकि वे संपादक द्वारा छंटनी किए जाते हैं

विकल्प 3

def query():
    sql = """select field1, field2, field3, field4
from table
where condition1=1
and condition2=2"""
    con = mymodule.get_connection()
    ...
  • मुझे यह विकल्प पसंद नहीं है क्योंकि यह अच्छी तरह से सारणीबद्ध कोड की स्पष्टता को तोड़ता है।

विकल्प 4

def query():
    sql = "select field1, field2, field3, field4 " \
          "from table " \
          "where condition1=1 " \
          "and condition2=2 "
    con = mymodule.get_connection()    
    ...
  • मुझे यह विकल्प पसंद नहीं है क्योंकि प्रत्येक पंक्ति में सभी अतिरिक्त टाइपिंग और क्वेरी को भी संपादित करना मुश्किल है।

मेरे लिए सबसे अच्छा समाधान विकल्प 2 होगा, लेकिन जब मैं sql स्ट्रिंग प्रिंट करता हूं तो मुझे अतिरिक्त व्हाट्सएप पसंद नहीं है।

क्या आप किसी अन्य विकल्प के बारे में जानते हैं?


यह वही है जिसे Psycopg लोग क्वेरी स्ट्रिंग्स की रचना के लिए a na tove अप्रोच कहते हैं, उदाहरण के लिए स्ट्रिंग कॉन्फैनेटेशन - initd.org/psycopg/docs/… । बजाय SQL इंजेक्शन के हमलों से बचने के लिए और SQL शाब्दिक से पायथन ऑब्जेक्ट्स को स्वचालित रूप से परिवर्तित करने के लिए क्वेरी मापदंडों का उपयोग करें। stackoverflow.com/questions/3134691/…
मैथ्यू कॉर्नेल

यह प्रश्न वास्तव में SQL प्रश्नों के लिए विशिष्ट नहीं है, लेकिन आमतौर पर पायथन में मल्टी-लाइन स्ट्रिंग्स को स्वरूपित करने के लिए लागू होता है। SQL टैग को हटा दिया जाना चाहिए।
cstork

जवाबों:


130

इस तरह के एक पुराने धागे को पोस्ट करने के लिए क्षमा करें - लेकिन किसी के रूप में जो भी पायथोनिक 'सबसे अच्छा' के लिए एक जुनून साझा करता है, मैंने सोचा कि मैं अपना समाधान साझा करूंगा।

इसका समाधान अजगर के स्ट्रिंग लिटरल कॉन्टेनेशन ( http://docs.python.org/ ) का उपयोग करके एसक्यूएल स्टेटमेंट का निर्माण करना है , जो विकल्प 2 और विकल्प 4 के बीच कहीं योग्य हो सकता है।

कोड नमूना:

sql = ("SELECT field1, field2, field3, field4 "
       "FROM table "
       "WHERE condition1=1 "
       "AND condition2=2;")

एफ-स्ट्रिंग्स के साथ भी काम करता है :

fields = "field1, field2, field3, field4"
table = "table"
conditions = "condition1=1 AND condition2=2"

sql = (f"SELECT {fields} "
       f"FROM {table} "
       f"WHERE {conditions};")

पेशेवरों:

  1. यह पायथोनिक 'अच्छी तरह से सारणीबद्ध' प्रारूप को बरकरार रखता है, लेकिन इसमें बाहरी अंतरिक्ष वर्ण (जो लॉगिंग को प्रदूषित करता है) नहीं जोड़ता है।
  2. यह विकल्प 4 के बैकलैश निरंतरता कुरूपता से बचा जाता है, जिससे बयानों को जोड़ना मुश्किल हो जाता है (सफेद-अंतरिक्ष अंधापन का उल्लेख नहीं करना)।
  3. और आगे, यह वास्तव में वीआईएम में बयान का विस्तार करने के लिए सरल है (बस सम्मिलित बिंदु पर कर्सर की स्थिति, और नई लाइन खोलने के लिए SHIFT-O दबाएं )।

1
यदि यह मुद्रण के लिए है, तो मुझे लगता है कि बेहतर विकल्प यह है कि इसे उत्परिवर्ती स्ट्रिंग के रूप में लिखें """और textwrap.dedent()आउटपुट करने से पहले उपयोग करें
slezica

मैंने उस विकल्प के साथ खेला, लेकिन इसने लॉग आउटपुट मल्टीलाइन भी बनाया। जब एक डीबी चेट्टी ऐप पर नज़र रखी जाती है, तो इससे वॉल्युमोज़ आउटपुट होता है।
user590028

1
यह एक पुराना धागा है, लेकिन मैं इस प्रारूप को एक सर्वोत्तम अभ्यास के रूप में उपयोग कर रहा हूं, हालांकि यह लंबे प्रश्नों के साथ थकाऊ है
Jabda

7
"sql query"SQL स्ट्रिंग्स (जो मानक के रूप में एकल उद्धरण का उपयोग करते हैं) के साथ खिलवाड़ करने से बचने के लिए क्या हमें हमेशा दोहरे उद्धरण चिह्नों का उपयोग नहीं करना चाहिए ?
tpvasconcelos

19

आपने स्पष्ट रूप से एसक्यूएल को लिखने के बहुत सारे तरीकों पर विचार किया है जैसे कि यह ठीक प्रिंट करता है, लेकिन डिबग लॉगिंग के लिए आपके द्वारा उपयोग किए जाने वाले 'प्रिंट' स्टेटमेंट को बदलने के बारे में कैसे आप अपने एसक्यूएल को उन तरीकों से लिखना पसंद करते हैं जो आपको पसंद नहीं हैं? ऊपर अपने पसंदीदा विकल्प का उपयोग करते हुए, कैसे एक लॉगिंग फ़ंक्शन के बारे में इस तरह:

def debugLogSQL(sql):
     print ' '.join([line.strip() for line in sql.splitlines()]).strip()

sql = """
    select field1, field2, field3, field4
    from table"""
if debug:
    debugLogSQL(sql)

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


11

सबसे साफ तरीका जो मैं भर में आया हूं, वह एसक्यूएल स्टाइल गाइड से प्रेरित है ।

sql = """
    SELECT field1, field2, field3, field4
      FROM table
     WHERE condition1 = 1
       AND condition2 = 2;
"""

अनिवार्य रूप से, जो कीवर्ड एक खंड शुरू करते हैं, उन्हें दाएं-संरेखित किया जाना चाहिए और फ़ील्ड नाम आदि को छोड़ दिया जाना चाहिए। यह बहुत साफ-सुथरा दिखता है और साथ ही साथ डिबग करना भी आसान है।


2
sql = ("select field1, field2, field3, field4 "
       "from table "
       "where condition1={} "
       "and condition2={}").format(1, 2)

Output: 'select field1, field2, field3, field4 from table 
         where condition1=1 and condition2=2'

यदि शर्त का मूल्य एक स्ट्रिंग होना चाहिए, तो आप इस तरह कर सकते हैं:

sql = ("select field1, field2, field3, field4 "
       "from table "
       "where condition1='{0}' "
       "and condition2='{1}'").format('2016-10-12', '2017-10-12')

Output: "select field1, field2, field3, field4 from table where
         condition1='2016-10-12' and condition2='2017-10-12'"

5
कृपया ऐसा कभी न करें। इसे SQL इंजेक्शन कहा जाता है और यह वास्तव में खतरनाक है। बहुत अधिक हर पायथन डेटाबेस लाइब्रेरी मापदंडों का उपयोग करने के लिए एक सुविधा प्रदान करता है। यदि आप format()SQL स्ट्रिंग्स के साथ खुद को पकड़ते हैं, तो यह एक प्रमुख कोड गंध है।
मटका 3

मुझे नहीं लगता कि हम इसका उपयोग नहीं कर सकते, आपको इसका उपयोग करने से पहले मापदंडों को मान्य करना होगा, और आपको पता होना चाहिए कि आप क्या पास करते हैं।
पंगपंग

मान्य करना एक बहुत अधिक त्रुटि प्रवण है जो केवल उपयोग करने where condition1=:field1और फिर मापदंडों के रूप में मूल्यों में गुजरने से है। यदि आप उपयोग कर रहे हैं .format(), तो ';DROP TABLE Usersआपके SQL में पॉप करने का एक तरीका है । मापदंडों का सही तरीके से उपयोग करने के लिए एक नज़र PEP-249 है। python.org/dev/peps/pep-0249/#paramstyle
Mattmc3

0

पूरी तरह से प्रारूपण से बचने के लिए , मुझे लगता है कि प्रक्रियाओं का उपयोग करने के लिए एक महान समाधान है ।

एक प्रक्रिया को कॉल करना आपको इस प्रक्रिया में जो भी क्वेरी डालना चाहता है, उसका परिणाम देता है । आप वास्तव में एक प्रक्रिया के भीतर कई प्रश्नों को संसाधित कर सकते हैं । कॉल केवल उस अंतिम क्वेरी को लौटाएगा जिसे कॉल किया गया था।

माई एसक्यूएल

DROP PROCEDURE IF EXISTS example;
 DELIMITER //
 CREATE PROCEDURE example()
   BEGIN
   SELECT 2+222+2222+222+222+2222+2222 AS this_is_a_really_long_string_test;
   END //
 DELIMITER;

#calling the procedure gives you the result of whatever query you want to put in this procedure. You can actually process multiple queries within a procedure. The call just returns the last query result
 call example;

अजगर

sql =('call example;')

-1

आप फ़ील्ड नामों को एक "फ़ील्ड" में रख सकते हैं, और फिर:


sql = 'select %s from table where condition1=1 and condition2=2' % (
 ', '.join(fields))

यदि आपकी शर्तों की सूची बढ़ती है, तो आप 'और' .join (शर्तों) का उपयोग करके भी ऐसा ही कर सकते हैं
jcomeau_ictx

आपके समाधान के साथ, Option_4 की तुलना में क्वेरी को संपादित करना और भी कठिन होगा, और इसे पढ़ना भी मुश्किल होगा।
ssoler

@ssoler, जो इस बात पर निर्भर करता है कि कोई चीजों को कैसे करता है। मैं अपने कार्यक्रमों में कुछ चर घोषित करता हूं, और इसके बजाय स्ट्रिंग्स के सरणियों का उपयोग करता हूं, जो उपरोक्त तरीकों को बहुत उपयोगी और बनाए रखने योग्य बनाता है , कम से कम मेरे द्वारा।
jcomeau_ictx

-1

मैं विकल्प 2 से चिपके रहने का सुझाव दूंगा (मैं हमेशा इसका उपयोग किसी भी अधिक जटिल प्रश्नों के लिए कर रहा हूं SELECT * FROM table) और यदि आप इसे अच्छे तरीके से प्रिंट करना चाहते हैं तो आप हमेशा एक अलग मॉड्यूल का उपयोग कर सकते हैं ।


-1

लघु प्रश्नों के लिए जो एक या दो पंक्तियों में फिट हो सकते हैं, मैं ऊपर दिए गए शीर्ष-समाधान में स्ट्रिंग शाब्दिक समाधान का उपयोग करता हूं। लंबे प्रश्नों के लिए, मैं उन्हें .sqlफ़ाइलों को तोड़ता हूं । मैं फ़ाइल को लोड करने और स्क्रिप्ट को निष्पादित करने के लिए एक आवरण फ़ंक्शन का उपयोग करता हूं, जैसे कुछ:

script_cache = {}
def execute_script(cursor,script,*args,**kwargs):
    if not script in script_cache:
        with open(script,'r') as s:
            script_cache[script] = s
    return cursor.execute(script_cache[script],*args,**kwargs)

बेशक यह अक्सर एक वर्ग के अंदर रहता है इसलिए मुझे आमतौर पर cursorस्पष्ट रूप से पास नहीं करना पड़ता है । मैं भी आमतौर पर उपयोग करता हूं codecs.open(), लेकिन यह सामान्य विचार भर में मिलता है। फिर SQL स्क्रिप्ट पूरी तरह से अपनी स्वयं की फाइलों में अपने स्वयं के सिंटैक्स हाइलाइटिंग के साथ स्व-निहित हैं।


-2
sql = """\
select field1, field2, field3, field4
from table
where condition1=1
and condition2=2
"""

[प्रतिक्रिया में संपादित करें टिप्पणी करने के लिए]
एक विधि के अंदर SQL स्ट्रिंग होने का मतलब यह नहीं है कि आपको इसे "सारणीबद्ध" करना है:

>>> class Foo:
...     def fubar(self):
...         sql = """\
... select *
... from frobozz
... where zorkmids > 10
... ;"""
...         print sql
...
>>> Foo().fubar()
select *
from frobozz
where zorkmids > 10
;
>>>

IMO यह Option_2
ssoler

@ लॉकर: आपके Option_2 में सभी लाइनों पर अग्रणी स्थान हैं; ध्यान दें कि आपका उदाहरण पहले प्रमुख स्थानों को छोड़ देता है select। मेरे जवाब में प्रमुख स्थान नहीं हैं। आप क्या राय बनाने के लिए नेतृत्व करते हैं कि वे समान हैं?
जॉन माकिन

यदि आप अपने sql स्ट्रिंग को एक विधि के अंदर रखते हैं तो आपको सभी लाइनों (Option_2) को सारणीबद्ध करना होगा। इसका एक संभावित समाधान Option_3 है।
ssoler

@ssoler: क्षमा करें, मुझे वह टिप्पणी समझ में नहीं आ रही है। कृपया मेरे अद्यतन उत्तर को देखें।
जॉन माकिन

आपका अपडेट किया गया उत्तर मेरा Option_3 है, है ना? मुझे यह विकल्प पसंद नहीं है क्योंकि यह अच्छी तरह से सारणीबद्ध कोड की स्पष्टता को तोड़ता है।
ssoler
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.