फ्लास्क- SQLAlchemy ऐप में कच्चे SQL को कैसे निष्पादित करें


219

SQLAlchemy में कच्चे SQL को कैसे निष्पादित करते हैं?

मेरे पास एक अजगर वेब ऐप है जो SQLAlchemy के माध्यम से फ्लास्क और डेटाबेस के इंटरफेस पर चलता है।

मुझे कच्चे एसक्यूएल को चलाने का एक तरीका चाहिए। इनलाइन विचारों के साथ क्वेरी में कई टेबल जॉइन शामिल हैं।

मैंने कोशिश की:

connection = db.session.connection()
connection.execute( <sql here> )

लेकिन मुझे गेटवे एरर मिलते रहते हैं।


5
मैंने उस पर पहले भी गौर किया है, लेकिन मुझे अपडेट चलाने का कोई ट्यूटोरियल नहीं मिला। मैं सिंटैक्स भी नहीं सीखूंगा और एसक्यूएल क्वेरी के बजाय एक लंबी (लगभग 20 पंक्तियाँ) को कवर करूँगा।
starwing123

103
@MarkusUnterwaditzer मैं ऐसा सोचता था, लेकिन अब मैं दृढ़ता से असहमत हूं। कच्चे, ठीक से पैराट्राइज्ड एसक्यूएल आमतौर पर फ़ंक्शन कॉल और ऑब्जेक्ट जो इसे उत्पन्न करते हैं की तुलना में पढ़ने और बनाए रखने में बहुत आसान है। यह ओआरएम को सही सिंटैक्स उत्पन्न करने के लिए हुप्स के माध्यम से कूदने के बिना डेटाबेस की पूरी क्षमताओं को भी प्रभावित करता है (यदि यह भी संभव है) और ओआरएम को अप्रत्याशित चीजें करने से रोकता है। आप सवाल पूछ सकते हैं, "फिर SQLAlchemy का उपयोग क्यों करें?", और मेरे पास एकमात्र उत्तर है, "मौजूदा एप्लिकेशन इसका उपयोग करता है और सब कुछ बदलना बहुत महंगा है।"
jpmc26

4
@ jpmc26 ने आपकी टिप्पणी को तोड़ दिया - SQL के एक प्रेमी के रूप में, मेरे पास एक गैर-जिम्मेदार कीमियागर के लिए "डेटाबेस की चाबी दूर करने" के विचार के साथ एक कठिन समय है और ORM की तरफ झुकना एक एंटीपर्टन है :) मैंने कहा कि मैं उपयोगकर्ता पंजीकरण / प्रबंधन जैसे कुछ घटकों में तेजी लाने के लिए उत्सुक हूं, और बटन के अनुक्रम के साथ तालिकाओं की पीढ़ी भी जिसके लिए मैं क्रिया + SQL कोड कर सकता हूं। क्या आप कुछ ओआरएम-स्केप्टिक-फ्रेंडली टूल्स में आए हैं जो आपके लिए पायथन फ्रेमवर्क में अच्छा काम करते हैं?
zx81

@ jpmc26 आप सी # डैपर की तरह एसक्यूएल या सुंदर पास का उपयोग करने के लिए पायथन फ्रेमवर्क में क्या उपयोग करते हैं? मैं पायथन वेब फ्रेमवर्क में जो कुछ भी देखता हूं वह चाहता है कि मैं SQLAlchemy का उपयोग करूं, और मुझे ORM पसंद नहीं है, और अगर मैं एक का उपयोग करता हूं, तो यह अत्यंत न्यूनतम है।
जॉनी

@ जॉनी मुझे खुद इसे आजमाने का अवसर नहीं मिला है, लेकिन कच्चे डेटाबेस कनेक्शन लाइब्रेरी शायद पर्याप्त हैं। उदाहरण के लिए, psycopg2 में ऐसे कर्सर हैं जो वापस आते हैं namedtupleऔर dictसीधे: initd.org/psycopg/docs/extras.html
jpmc26

जवाबों:


310

आपने कोशिश की है:

result = db.engine.execute("<sql here>")

या:

from sqlalchemy import text

sql = text('select name from penguins')
result = db.engine.execute(sql)
names = [row[0] for row in result]
print names

7
यदि आप एक प्रविष्टि या अपडेट करते हैं, तो आप लेनदेन कैसे करते हैं?
डेविड एस

14
यदि आप कच्ची एसक्यूएल का उपयोग कर रहे हैं तो आप लेन-देन को नियंत्रित करते हैं, इसलिए आपको खुद को BEGINऔर COMMITस्टेटमेंट जारी करना होगा ।
मिगुएल

1
जब आप SQLAlchemy के बिना उन्हें जारी करते हैं तो क्या वही SQL कमांड काम करता है? आप अपने डेटाबेस पर डिबगिंग सक्षम करना चाह सकते हैं ताकि आप देख सकें कि यह किस कमांड को निष्पादित कर रहा है।
मिगुएल

27
db.engine.execute(text("<sql here>")).execution_options(autocommit=True))उस पर अमल भी करता है और करता भी है।
देवी

8
@ मिगेल "यदि आप कच्ची एसक्यूएल का उपयोग कर रहे हैं तो आप लेनदेन को नियंत्रित करते हैं, इसलिए आपको बेगिन जारी करना होगा और अपने आप को कमिट करना होगा।" यह बिल्कुल सही नहीं है। आप एक सत्र वस्तु के साथ कच्चे एसक्यूएल का उपयोग कर सकते हैं। बस इस टिप्पणी पर ध्यान दिया है, लेकिन आप कच्चे एसक्यूएल के साथ एक सत्र का उपयोग करने के लिए मेरा जवाब देख सकते हैं।
jpmc26

180

SQL कीमिया सत्र वस्तुओं का अपना executeतरीका है:

result = db.session.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})

आपके सभी एप्लिकेशन क्वेरी सत्र ऑब्जेक्ट के माध्यम से होने चाहिए, चाहे वे कच्चे SQL हों या नहीं। यह सुनिश्चित करता है कि प्रश्नों को एक लेनदेन द्वारा ठीक से प्रबंधित किया जाता है , जो एक ही इकाई में एक ही अनुरोध के रूप में एकाधिक प्रश्नों को प्रतिबद्ध या वापस करने की अनुमति देता है। इंजन या कनेक्शन का उपयोग करके लेनदेन के बाहर जाने से आपको सूक्ष्म रूप से अधिक जोखिम होता है, संभवतः उन बगों का पता लगाना कठिन होता है जो आपको दूषित डेटा के साथ छोड़ सकते हैं। प्रत्येक अनुरोध को केवल एक लेन-देन के साथ जोड़ा जाना चाहिए, और db.sessionयह सुनिश्चित करना कि यह आपके आवेदन के लिए मामला है।

यह भी ध्यान रखें कि पैरामीटर प्रश्नों केexecute लिए डिज़ाइन किया गया है । SQL इंजेक्शन के हमलों से खुद को बचाने के लिए क्वेरी के लिए किसी भी इनपुट के लिए, उदाहरण के लिए , जैसे मापदंडों का उपयोग करें । आप इन मापदंडों के लिए दूसरा तर्क के रूप में मान प्रदान कर सकते हैं , जहां प्रत्येक कुंजी पैरामीटर का नाम है जैसा कि क्वेरी में दिखाई देता है। आपके डेटाबेस के आधार पर पैरामीटर का सटीक सिंटैक्स स्वयं भिन्न हो सकता है, लेकिन सभी प्रमुख रिलेशनल डेटाबेस किसी न किसी रूप में उनका समर्थन करते हैं।:valdict

मान लिया जाये कि यह एक है SELECTक्वेरी, इस वापस आ जाएगी एक iterable की RowProxyवस्तुओं।

आप विभिन्न तकनीकों के साथ अलग-अलग कॉलम एक्सेस कर सकते हैं:

for r in result:
    print(r[0]) # Access by positional index
    print(r['my_column']) # Access by column name as a string
    r_dict = dict(r.items()) # convert to dict keyed by column names

व्यक्तिगत रूप से, मैं परिणामों को namedtuples में बदलना पसंद करता हूं :

from collections import namedtuple

Record = namedtuple('Record', result.keys())
records = [Record(*r) for r in result.fetchall()]
for r in records:
    print(r.my_column)
    print(r)

यदि आप फ्लास्क-SQLAlchemy एक्सटेंशन का उपयोग नहीं कर रहे हैं, तो आप अभी भी आसानी से एक सत्र का उपयोग कर सकते हैं:

import sqlalchemy
from sqlalchemy.orm import sessionmaker, scoped_session

engine = sqlalchemy.create_engine('my connection string')
Session = scoped_session(sessionmaker(bind=engine))

s = Session()
result = s.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})

एक चयन एक ResultProxy वापस आ जाएगी।
एलन बी

@AlanB हां। मैंने अपने शब्दों को खराब तरीके से चुना जब मैंने इसे एक अनुक्रम कहा, इसका अर्थ है कि यह अनुक्रम प्रोटोकॉल को लागू करता है। मैंने सुधारा और स्पष्ट किया है। धन्यवाद।
jpmc26

@ jpmc26 को db.session.close () जैसी क्वेरी को निष्पादित करने के बाद सत्र बंद होना चाहिए? और क्या अब भी कनेक्शन पूलिंग के लाभ होंगे?
रवि मल्होत्रा

58

डॉक्स: SQL अभिव्यक्ति भाषा ट्यूटोरियल - पाठ का उपयोग करना

उदाहरण:

from sqlalchemy.sql import text

connection = engine.connect()

# recommended
cmd = 'select * from Employees where EmployeeGroup = :group'
employeeGroup = 'Staff'
employees = connection.execute(text(cmd), group = employeeGroup)

# or - wee more difficult to interpret the command
employeeGroup = 'Staff'
employees = connection.execute(
                  text('select * from Employees where EmployeeGroup = :group'), 
                  group = employeeGroup)

# or - notice the requirement to quote 'Staff'
employees = connection.execute(
                  text("select * from Employees where EmployeeGroup = 'Staff'"))


for employee in employees: logger.debug(employee)
# output
(0, 'Tim', 'Gurra', 'Staff', '991-509-9284')
(1, 'Jim', 'Carey', 'Staff', '832-252-1910')
(2, 'Lee', 'Asher', 'Staff', '897-747-1564')
(3, 'Ben', 'Hayes', 'Staff', '584-255-2631')

1
Sqlalchemy डॉक्स का लिंक पुराना हो चुका है। यह हाल ही का है: docs.sqlalchemy.org/en/latest/core/…
कार्ल

1
क्या मैं पूछ सकता हूं कि हम क्यों इस्तेमाल कर रहे हैं ==?
नमस्ते जी वीयू

1
@ जेक बर्गर आपके लिए एक बड़ा धन्यवाद। मैंने इस उत्तर की तलाश में लगभग एक दिन बर्बाद कर दिया है। मैं सिर्फ पाठ को रूपांतरित किए बिना सीधे sql को निष्पादित कर रहा था। जब भी हमारे क्लाज में%% छात्र होते हैं, तो यह त्रुटि थी। आपके उत्तर के लिए एक बड़ी प्रशंसा।
सुरेश कुमार

1
@NGGVU क्योंकि अधिकांश प्रोग्रामिंग भाषाओं में, =सामान्य रूप से एक मान निर्दिष्ट करने के लिए आरक्षित है ; जबकि मूल्यों की तुलना करने== के लिए आरक्षित है
जेक बर्गर

2
@JakeBerger क्या आपके पास उसके लिए लिंक है? SQL ऐसी भाषा नहीं है, और SQLAlchemy डॉक्स द्वारा निर्णय लेना ऐसा नहीं है।
जॉन्डोडो

36

आप का उपयोग कर चयन एसक्यूएल प्रश्नों के परिणाम प्राप्त कर सकते from_statement()हैं और text()के रूप में दिखाया यहाँ । आप इस तरह से tuples से निपटने की जरूरत नहीं है। एक वर्ग के लिए एक उदाहरण के रूप Userमें तालिका का नाम usersजिसे आप आज़मा सकते हैं,

from sqlalchemy.sql import text
.
.
.
user = session.query(User).from_statement(
    text("SELECT * FROM users where name=:name")).\
    params(name='ed').all()

return user

15
result = db.engine.execute(text("<sql here>"))

निष्पादित करता है, <sql here>लेकिन जब तक आप autocommitमोड पर नहीं होते हैं तब तक यह प्रतिबद्ध नहीं है। इसलिए, आवेषण और अद्यतन डेटाबेस में प्रतिबिंबित नहीं होंगे।

परिवर्तनों के बाद करने के लिए, करें

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))

2

फ्लास्क शेल से SQL क्वेरी को कैसे चलाना है, इसका एक सरलीकृत उत्तर है

सबसे पहले, अपने मॉड्यूल को मैप करें (यदि आपका मॉड्यूल / ऐप प्रिंसिपल फ़ोल्डर में मैनेजमेड है और आप UNIX ऑपरेटिंग सिस्टम में हैं), चलाएं:

export FLASK_APP=manage

फ्लास्क शेल चलाएं

flask shell

आयात करें जो हमें चाहिए ::

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
from sqlalchemy import text

अपनी क्वेरी चलाएँ:

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))

यह वर्तमान में डेटाबेस कनेक्शन का उपयोग करता है जिसमें एप्लिकेशन है।


0

क्या आपने डॉक्स मेंconnection.execute(text( <sql here> ), <bind params here> ) वर्णित मापदंडों का उपयोग करने और बांधने की कोशिश की है ? यह कई पैरामीटर स्वरूपण और प्रदर्शन समस्याओं को हल करने में मदद कर सकता है। शायद गेटवे एरर एक टाइमआउट है? बाइंड पैरामीटर जटिल प्रश्नों को काफी तेजी से निष्पादित करते हैं।


2
डॉक्स के अनुसार , यह होना चाहिए connection.execute(text(<sql here>), <bind params> )bind paramsनहीं होना चाहिए text()निष्पादित करने के लिए बाइंड मापदंडों में खिला () विधि
जेक बर्गर

जेक का लिंक टूट गया है। मुझे लगता है कि यह URL अब प्रासंगिक है: docs.sqlalchemy.org/en/latest/core/…
code_dredd

-1

आप tuples से बचने के लिए चाहते हैं, एक और तरीका है फोन करके है first, oneया allतरीके:

query = db.engine.execute("SELECT * FROM blogs "
                           "WHERE id = 1 ")

assert query.first().name == "Welcome to my blog"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.