Skip to content

TST/DOC #10846 Test and document use of SQLAlchemy expressions in read_sql() #10983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions doc/source/io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3918,6 +3918,42 @@ connecting to.
For more information see the examples the SQLAlchemy `documentation <http://docs.sqlalchemy.org/en/rel_0_9/core/engines.html>`__


Advanced SQLAlchemy queries
~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can use SQLAlchemy constructs to describe your query.

Use :func:`sqlalchemy.text` to specify query parameters in a backend-neutral way

.. ipython:: python

import sqlalchemy as sa
pd.read_sql(sa.text('SELECT * FROM data where Col_1=:col1'), engine, params={'col1': 'X'})

If you have an SQLAlchemy description of your database you can express where conditions using SQLAlchemy expressions

.. ipython:: python

metadata = sa.MetaData()
data_table = sa.Table('data', metadata,
sa.Column('index', sa.Integer),
sa.Column('Date', sa.DateTime),
sa.Column('Col_1', sa.String),
sa.Column('Col_2', sa.Float),
sa.Column('Col_3', sa.Boolean),
)

pd.read_sql(sa.select([data_table]).where(data_table.c.Col_3 == True), engine)

You can combine SQLAlchemy expressions with parameters passed to :func:`read_sql` using :func:`sqlalchemy.bindparam`

.. ipython:: python

import datetime as dt
expr = sa.select([data_table]).where(data_table.c.Date > sa.bindparam('date'))
pd.read_sql(expr, engine, params={'date': dt.datetime(2010, 10, 18)})


Sqlite fallback
'''''''''''''''

Expand Down
10 changes: 5 additions & 5 deletions pandas/io/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,9 @@ def read_sql_query(sql, con, index_col=None, coerce_float=True, params=None,

Parameters
----------
sql : string
SQL query to be executed
con : SQLAlchemy connectable(engine/connection) or database string URI
sql : string SQL query or SQLAlchemy Selectable (select or text object)
to be executed.
con : SQLAlchemy connectable(engine/connection) or database string URI
or sqlite3 DBAPI2 connection
Using SQLAlchemy makes it possible to use any DB supported by that
library.
Expand Down Expand Up @@ -423,8 +423,8 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,

Parameters
----------
sql : string
SQL query to be executed or database table name.
sql : string SQL query or SQLAlchemy Selectable (select or text object)
to be executed, or database table name.
con : SQLAlchemy connectable(engine/connection) or database string URI
or DBAPI2 connection (fallback mode)
Using SQLAlchemy makes it possible to use any DB supported by that
Expand Down
29 changes: 29 additions & 0 deletions pandas/io/tests/test_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,35 @@ def test_to_sql_read_sql_with_database_uri(self):
tm.assert_frame_equal(test_frame1, test_frame3)
tm.assert_frame_equal(test_frame1, test_frame4)

def _make_iris_table_metadata(self):
sa = sqlalchemy
metadata = sa.MetaData()
iris = sa.Table('iris', metadata,
sa.Column('SepalLength', sa.REAL),
sa.Column('SepalWidth', sa.REAL),
sa.Column('PetalLength', sa.REAL),
sa.Column('PetalWidth', sa.REAL),
sa.Column('Name', sa.TEXT)
)

return iris

def test_query_by_text_obj(self):
# WIP : GH10846
name_text = sqlalchemy.text('select * from iris where name=:name')
iris_df = sql.read_sql(name_text, self.conn, params={'name': 'Iris-versicolor'})
all_names = set(iris_df['Name'])
self.assertEqual(all_names, set(['Iris-versicolor']))

def test_query_by_select_obj(self):
# WIP : GH10846
iris = self._make_iris_table_metadata()

name_select = sqlalchemy.select([iris]).where(iris.c.Name == sqlalchemy.bindparam('name'))
iris_df = sql.read_sql(name_select, self.conn, params={'name': 'Iris-setosa'})
all_names = set(iris_df['Name'])
self.assertEqual(all_names, set(['Iris-setosa']))


class _EngineToConnMixin(object):
"""
Expand Down