330

How do you execute raw SQL in SQLAlchemy?

I have a python web app that runs on flask and interfaces to the database through SQLAlchemy.

I need a way to run the raw SQL. The query involves multiple table joins along with Inline views.

I've tried:

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

But I keep getting gateway errors.

roganjosh
  • 12,594
  • 4
  • 29
  • 46
starwing123
  • 3,413
  • 3
  • 13
  • 7
  • 7
    I've looked at that before, but I couldn't find a tutorial on running an update. I'd also rather not learn the syntax and covert a rather long (about 20 lines) SQL query. – starwing123 Jul 31 '13 at 15:00
  • 142
    @MarkusUnterwaditzer I used to think that, but now I strongly disagree. Raw, properly parametrized SQL is generally much easier to read and maintain than a bunch of function calls and objects that generate it. It also affords you the full capabilities of the database without having to jump through hoops to make the ORM generate the correct syntax (if it's even possible) and keeps the ORM from doing unexpected things. You might ask the question, "Then why use SQLAlchemy at all?", and the only answer I have is, "The existing application uses it and changing everything is too expensive." – jpmc26 Feb 28 '14 at 02:05
  • 7
    @jpmc26 Upped your comment—as a lover of SQL, I have a hard time with the idea of "giving away the keys to the database" to an irresponsible alchemist and tend to lean on the side of [ORM is an antipattern](http://seldo.com/weblog/2011/08/11/orm_is_an_antipattern) :) That being said I'd be keen to accelerate certain components, such as user registration/management, and also the generation of tables with sequences of buttons for which I can code the actions + SQL. Have you come across some ORM-skeptic-friendly tools that work well for you in a Python framework? – zx81 Jul 17 '15 at 05:04
  • 1
    @jpmc26 What do you use in a Python framework to use just SQL or pretty close like C# Dapper? Everything I see in a Python web framework wants me to use SQLAlchemy, and I do not like an ORM, and if I do use one, it is extremely minimal. – johnny Apr 05 '17 at 19:14
  • @johnny I haven't had the opportunity to try it myself, but the raw database connection libraries are probably enough. For example, psycopg2 has cursors that return `namedtuple` and `dict` directly: http://initd.org/psycopg/docs/extras.html. – jpmc26 Apr 05 '17 at 19:18
  • 1
    The accepted answer is deprecated. See @Demitri's answer below. – Deepam Gupta Oct 18 '21 at 06:39

10 Answers10

416

Have you tried:

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

or:

from sqlalchemy import text

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

Note that db.engine.execute() is "connectionless", which is deprecated in SQLAlchemy 2.0.

Demitri
  • 13,134
  • 4
  • 40
  • 41
Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • 10
    If you do an insert or update, how do you commit the transaction? – David S Jan 30 '14 at 23:01
  • 17
    If you are using raw SQL then you control the transactions, so you have to issue the `BEGIN` and `COMMIT` statements yourself. – Miguel Grinberg Jan 30 '14 at 23:47
  • I've tried that and it doesn't seem to work for me. Very curious. – David S Jan 31 '14 at 00:51
  • 1
    Does the same SQL commands work when you issue them without SQLAlchemy? You may want to enable debugging on your database so that you can see what commands it is executing. – Miguel Grinberg Jan 31 '14 at 04:44
  • 1
    Yes, it works. And I'm dumping the result to my app logs (so I can see it come back). And I can see it in the postgres logs. it just doesn't get commited. For more details, I've started question at: http://stackoverflow.com/questions/21469884/commiting-a-transaction-from-a-postgresql-function-in-flask – David S Jan 31 '14 at 15:35
  • 35
    ```db.engine.execute(text("")).execution_options(autocommit=True))``` executes and commits it too. – Devi Sep 04 '15 at 05:27
  • 12
    @Miguel "If you are using raw SQL then you control the transactions, so you have to issue the BEGIN and COMMIT statements yourself." This is simply not true. You can use raw SQL with a session object. Just noticed this comment, but you can see my answer for how to use a session with raw SQL. – jpmc26 Sep 11 '15 at 20:41
  • 7
    May I know why we need to wrap query in `text(...)` ? – Nam G VU Nov 20 '17 at 16:39
  • 1
    @NamGVU: the [documentation](http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.text) has the answer to your question. – Miguel Grinberg Nov 22 '17 at 00:21
  • I get the idea of parameter binding but not the context in our answer. Would you shed light on me? – Nam G VU Nov 22 '17 at 01:26
  • for select, is it necessary to close the connection after result = db.engine.execute(sql). – Ferdous Wahid Nov 18 '18 at 14:18
  • @jpmc26, I believe Miguel is talking about using transactions, https://docs.sqlalchemy.org/en/13/core/connections.html#using-transactions, you just need to change this line "with engine.connect() as connection:" to "with db.engine.connect() as connection:" since were using Flask-SQLAlchemy. This will create the "BEGIN" and "COMMIT" automatically. – joemalski Jun 19 '20 at 13:50
  • @joemalski The response is still wrong. Executing raw SQL still uses the transaction semantics associated with the object used to execute it, just like any other kind of SQL command issued using that object. You don't have to issue them yourself unless the *connection* or *session* object somehow forces you to do that with any query; there's no special status for raw SQL. Your reply is wrong, too. The call is `engine.begin()` according to your link. – jpmc26 Jun 30 '20 at 08:24
  • It will not work in SQLalchemy > 2.0. Refer: https://stackoverflow.com/questions/75316741/attributeerror-engine-object-has-no-attribute-execute-when-trying-to-run-sq – Joseph Cen Sep 02 '23 at 08:44
279

SQL Alchemy session objects have their own execute method:

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

All your application queries should be going through a session object, whether they're raw SQL or not. This ensures that the queries are properly managed by a transaction, which allows multiple queries in the same request to be committed or rolled back as a single unit. Going outside the transaction using the engine or the connection puts you at much greater risk of subtle, possibly hard to detect bugs that can leave you with corrupted data. Each request should be associated with only one transaction, and using db.session will ensure this is the case for your application.

Also take note that execute is designed for parameterized queries. Use parameters, like :val in the example, for any inputs to the query to protect yourself from SQL injection attacks. You can provide the value for these parameters by passing a dict as the second argument, where each key is the name of the parameter as it appears in the query. The exact syntax of the parameter itself may be different depending on your database, but all of the major relational databases support them in some form.

Assuming it's a SELECT query, this will return an iterable of RowProxy objects.

You can access individual columns with a variety of techniques:

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

Personally, I prefer to convert the results into 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)

If you're not using the Flask-SQLAlchemy extension, you can still easily use a session:

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})
jpmc26
  • 28,463
  • 14
  • 94
  • 146
  • 1
    A Select will return a ResultProxy. – Alan B Aug 02 '19 at 14:27
  • @AlanB Yes. I chose my words poorly when I called it a sequence, implying it implements the sequence protocol. I've corrected and clarified. Thanks. – jpmc26 Aug 06 '19 at 04:38
  • 2
    @jpmc26 should be close the session after executing the query like db.session.close()? And will it still have the benefits of connection pooling? – ravi malhotra Mar 17 '20 at 12:29
  • dict(r.items()) its works. make sure you have proper version of these two packages. SQLAlchemy=<1.3.5, Flask-SQLAlchemy=<2.4.1 – Ramesh Ponnusamy Aug 30 '21 at 10:36
  • With these I was always getting lists and `TypeError: list indices` errors ... So finally I went with `results = db_session.query("my_table")........ .all()` and then `for row in results:` and then `row.my_column` worked, or if you have a the column name in a variable => then I recommend `getattr(row, column_name_str_variable)` – jave.web Sep 09 '21 at 15:23
71

You can get the results of SELECT SQL queries using from_statement() and text() as shown here. You don't have to deal with tuples this way. As an example for a class User having the table name users you can try,

from sqlalchemy.sql import text

user = session.query(User).from_statement(
    text("""SELECT * FROM users where name=:name""")
).params(name="ed").all()

return user
Ryabchenko Alexander
  • 10,057
  • 7
  • 56
  • 88
TrigonaMinima
  • 1,828
  • 1
  • 23
  • 35
69

docs: SQL Expression Language Tutorial - Using Text

example:

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')
Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
Jake Berger
  • 5,237
  • 1
  • 28
  • 22
  • 1
    The link to the sqlalchemy docs appears to be out of date. This is more recent: http://docs.sqlalchemy.org/en/latest/core/tutorial.html#using-textual-sql – Carl Jul 05 '16 at 15:46
  • 1
    May I ask why we using `==`? – Nam G VU Nov 20 '17 at 17:29
  • 1
    @Jake Berger a big thanks for you. I've wasted almost a day in search of this answer. I was just directly executing the sql without converting to text. It was throwing error whenever we have %students% in my where clause. A big applause for your answer. – Suresh Kumar Jan 27 '18 at 04:16
  • 1
    @NamGVU because like in most programming languages, `=` is normally reserved for _assigning_ a value; whereas `==` is reserved for _comparing_ values – Jake Berger Jan 30 '18 at 17:31
  • Thanks for clarified. I didn't know we can use == in sqlalchemy for where clause, now I do. – Nam G VU Feb 06 '18 at 02:19
  • 2
    @JakeBerger Do you have a link for that? SQL is not such a language, and judging by the [SQLAlchemy docs](https://docs.sqlalchemy.org/en/13/core/tutorial.html#using-textual-sql) this is not so. – johndodo Oct 21 '19 at 05:31
  • Of [MySQL](https://dev.mysql.com/doc/refman/5.7/en/non-typed-operators.html), [PostgreSQL](https://www.postgresql.org/docs/current/functions-comparison.html), [MS SQL](https://docs.microsoft.com/en-us/sql/t-sql/language-elements/comparison-operators-transact-sql?view=sql-server-ver15), [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Comparison-Conditions.html#GUID-2590303E-81FE-4758-A971-1EE8B798951F), and [SQLite](https://sqlite.org/lang_expr.html#operators), only SQLite allows `==` for equality tests. All of them allow `=`, the standard SQL equality operator. – jpmc26 Nov 09 '19 at 01:45
51

For SQLAlchemy ≥ 1.4

Starting in SQLAlchemy 1.4, connectionless or implicit execution has been deprecated, i.e.

db.engine.execute(...) # DEPRECATED

as well as bare strings as queries.

The new API requires an explicit connection, e.g.

from sqlalchemy import text

with db.engine.connect() as connection:
    result = connection.execute(text("SELECT * FROM ..."))
    for row in result:
        # ...

Similarly, it’s encouraged to use an existing Session if one is available:

result = session.execute(sqlalchemy.text("SELECT * FROM ..."))

or using parameters:

session.execute(sqlalchemy.text("SELECT * FROM a_table WHERE a_column = :val"),
                {'val': 5})

See "Connectionless Execution, Implicit Execution" in the documentation for more details.

Demitri
  • 13,134
  • 4
  • 40
  • 41
14
result = db.engine.execute(text("<sql here>"))

executes the <sql here> but doesn't commit it unless you're on autocommit mode. So, inserts and updates wouldn't reflect in the database.

To commit after the changes, do

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))
Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
Devi
  • 5,023
  • 1
  • 34
  • 27
2

This is a simplified answer of how to run SQL query from Flask Shell

First, map your module (if your module/app is manage.py in the principal folder and you are in a UNIX Operating system), run:

export FLASK_APP=manage

Run Flask shell

flask shell

Import what we need::

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

Run your query:

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

This use the currently database connection which has the application.

Luigi Lopez
  • 1,037
  • 10
  • 23
1

Flask-SQLAlchemy v: 3.0.x / SQLAlchemy v: 1.4

users = db.session.execute(db.select(User).order_by(User.title.desc()).limit(150)).scalars()

So basically for the latest stable version of the flask-sqlalchemy specifically the documentation suggests using the session.execute() method in conjunction with the db.select(Object).

Panagiss
  • 3,154
  • 2
  • 20
  • 34
0

Have you tried using connection.execute(text( <sql here> ), <bind params here> ) and bind parameters as described in the docs? This can help solve many parameter formatting and performance problems. Maybe the gateway error is a timeout? Bind parameters tend to make complex queries execute substantially faster.

SuperShoot
  • 9,880
  • 2
  • 38
  • 55
jhnwsk
  • 971
  • 12
  • 15
  • 2
    according to [docs](http://docs.sqlalchemy.org/en/rel_0_8/core/tutorial.html#using-text), it should be `connection.execute(text(), )`. `bind params` should NOT be in `text()`. _feeding in the bind parameters to the execute() method_ – Jake Berger Sep 15 '13 at 03:54
  • Jake's link is broken. I think this is the URL that's relevant now: https://docs.sqlalchemy.org/en/latest/core/sqlelement.html?highlight=text#sqlalchemy.sql.expression.text – code_dredd Mar 04 '19 at 20:13
-1

If you want to avoid tuples, another way is by calling the first, one or all methods:

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

assert query.first().name == "Welcome to my blog"
Joe Gasewicz
  • 1,252
  • 15
  • 20