diff --git a/doc/source/whatsnew/v0.17.0.txt b/doc/source/whatsnew/v0.17.0.txt index 70d616ca72c1b..dd8e1f89d7b38 100644 --- a/doc/source/whatsnew/v0.17.0.txt +++ b/doc/source/whatsnew/v0.17.0.txt @@ -142,6 +142,9 @@ Other enhancements - ``pd.merge`` will now allow duplicate column names if they are not merged upon (:issue:`10639`). - ``pd.pivot`` will now allow passing index as ``None`` (:issue:`3962`). + +- ``read_sql_table`` will now allow reading from views (:issue:`10750`). + - ``drop_duplicates`` and ``duplicated`` now accept ``keep`` keyword to target first, last, and all duplicates. ``take_last`` keyword is deprecated, see :ref:`deprecations ` (:issue:`6511`, :issue:`8505`) .. ipython :: python diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 8eefe4ba98876..b587ec128c016 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -337,7 +337,7 @@ def read_sql_table(table_name, con, schema=None, index_col=None, from sqlalchemy.schema import MetaData meta = MetaData(con, schema=schema) try: - meta.reflect(only=[table_name]) + meta.reflect(only=[table_name], views=True) except sqlalchemy.exc.InvalidRequestError: raise ValueError("Table %s not found" % table_name) diff --git a/pandas/io/tests/test_sql.py b/pandas/io/tests/test_sql.py index 859c6d3250121..619de8d6bad3b 100644 --- a/pandas/io/tests/test_sql.py +++ b/pandas/io/tests/test_sql.py @@ -161,6 +161,12 @@ SELECT * FROM iris WHERE "Name"=%(name)s AND "SepalLength"=%(length)s """ + }, + 'create_view': { + 'sqlite': """ + CREATE VIEW iris_view AS + SELECT * FROM iris + """ } } @@ -244,6 +250,10 @@ def _load_iris_data(self): for row in r: self._get_exec().execute(ins, row) + def _load_iris_view(self): + self.drop_table('iris_view') + self._get_exec().execute(SQL_STRINGS['create_view'][self.flavor]) + def _check_iris_loaded_frame(self, iris_frame): pytype = iris_frame.dtypes[0].type row = iris_frame.iloc[0] @@ -482,6 +492,7 @@ class _TestSQLApi(PandasSQLTest): def setUp(self): self.conn = self.connect() self._load_iris_data() + self._load_iris_view() self._load_test1_data() self._load_test2_data() self._load_test3_data() @@ -492,6 +503,11 @@ def test_read_sql_iris(self): "SELECT * FROM iris", self.conn) self._check_iris_loaded_frame(iris_frame) + def test_read_sql_view(self): + iris_frame = sql.read_sql_query( + "SELECT * FROM iris_view", self.conn) + self._check_iris_loaded_frame(iris_frame) + def test_legacy_read_frame(self): with tm.assert_produces_warning(FutureWarning): iris_frame = sql.read_frame(