-
-
Notifications
You must be signed in to change notification settings - Fork 18.7k
ENH: add schema support to sql functions #7952
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -429,6 +429,13 @@ Enhancements | |
|
||
- Added support for a ``chunksize`` parameter to ``to_sql`` function. This allows DataFrame to be written in chunks and avoid packet-size overflow errors (:issue:`8062`) | ||
- Added support for writing ``datetime.date`` and ``datetime.time`` object columns with ``to_sql`` (:issue:`6932`). | ||
- Added support for specifying a ``schema`` to read from/write to with ``read_sql_table`` and ``to_sql`` (:issue:`7441`, :issue:`7952`). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe bigger add code-block example? (like above), link-to-docs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
For example: | ||
|
||
.. code-block:: python | ||
|
||
df.to_sql('table', engine, schema='other_schema') | ||
pd.read_sql_table('table', engine, schema='other_schema') | ||
|
||
- Added support for bool, uint8, uint16 and uint32 datatypes in ``to_stata`` (:issue:`7097`, :issue:`7365`) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,7 +28,7 @@ | |
|
||
from datetime import datetime, date, time | ||
|
||
from pandas import DataFrame, Series, Index, MultiIndex, isnull | ||
from pandas import DataFrame, Series, Index, MultiIndex, isnull, concat | ||
from pandas import date_range, to_datetime, to_timedelta | ||
import pandas.compat as compat | ||
from pandas.compat import StringIO, range, lrange, string_types | ||
|
@@ -457,12 +457,12 @@ def test_roundtrip(self): | |
tm.assert_frame_equal(result, self.test_frame1) | ||
|
||
def test_roundtrip_chunksize(self): | ||
sql.to_sql(self.test_frame1, 'test_frame_roundtrip', con=self.conn, | ||
sql.to_sql(self.test_frame1, 'test_frame_roundtrip', con=self.conn, | ||
index=False, flavor='sqlite', chunksize=2) | ||
result = sql.read_sql_query( | ||
'SELECT * FROM test_frame_roundtrip', | ||
con=self.conn) | ||
tm.assert_frame_equal(result, self.test_frame1) | ||
tm.assert_frame_equal(result, self.test_frame1) | ||
|
||
def test_execute_sql(self): | ||
# drop_sql = "DROP TABLE IF EXISTS test" # should already be done | ||
|
@@ -591,13 +591,13 @@ def test_to_sql_index_label_multiindex(self): | |
index_label='C') | ||
|
||
def test_multiindex_roundtrip(self): | ||
df = DataFrame.from_records([(1,2.1,'line1'), (2,1.5,'line2')], | ||
df = DataFrame.from_records([(1,2.1,'line1'), (2,1.5,'line2')], | ||
columns=['A','B','C'], index=['A','B']) | ||
|
||
df.to_sql('test_multiindex_roundtrip', self.conn) | ||
result = sql.read_sql_query('SELECT * FROM test_multiindex_roundtrip', | ||
result = sql.read_sql_query('SELECT * FROM test_multiindex_roundtrip', | ||
self.conn, index_col=['A','B']) | ||
tm.assert_frame_equal(df, result, check_index_type=True) | ||
tm.assert_frame_equal(df, result, check_index_type=True) | ||
|
||
def test_integer_col_names(self): | ||
df = DataFrame([[1, 2], [3, 4]], columns=[0, 1]) | ||
|
@@ -1196,8 +1196,8 @@ class TestPostgreSQLAlchemy(_TestSQLAlchemy): | |
flavor = 'postgresql' | ||
|
||
def connect(self): | ||
return sqlalchemy.create_engine( | ||
'postgresql+{driver}://postgres@localhost/pandas_nosetest'.format(driver=self.driver)) | ||
url = 'postgresql+{driver}://postgres@localhost/pandas_nosetest' | ||
return sqlalchemy.create_engine(url.format(driver=self.driver)) | ||
|
||
def setup_driver(self): | ||
try: | ||
|
@@ -1213,6 +1213,61 @@ def tearDown(self): | |
for table in c.fetchall(): | ||
self.conn.execute("DROP TABLE %s" % table[0]) | ||
|
||
def test_schema_support(self): | ||
# only test this for postgresql (schema's not supported in mysql/sqlite) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you have a test which raises in mysql/sqlite? (and checks the non-suppor error) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now, I don't check or catch anything here in pandas, but just let sqlalchemy (or the underlying dbapi driver) do the work. So for sqlite, using For mysql, it actually does work. Mysql does not have a distinct 'schema' concept, but schema is actually some kind of alias for table. So using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But as it are not errors raised in pandas, I don't test for them. |
||
df = DataFrame({'col1':[1, 2], 'col2':[0.1, 0.2], 'col3':['a', 'n']}) | ||
|
||
# create a schema | ||
self.conn.execute("DROP SCHEMA IF EXISTS other CASCADE;") | ||
self.conn.execute("CREATE SCHEMA other;") | ||
|
||
# write dataframe to different schema's | ||
df.to_sql('test_schema_public', self.conn, index=False) | ||
df.to_sql('test_schema_public_explicit', self.conn, index=False, | ||
schema='public') | ||
df.to_sql('test_schema_other', self.conn, index=False, schema='other') | ||
|
||
# read dataframes back in | ||
res1 = sql.read_sql_table('test_schema_public', self.conn) | ||
tm.assert_frame_equal(df, res1) | ||
res2 = sql.read_sql_table('test_schema_public_explicit', self.conn) | ||
tm.assert_frame_equal(df, res2) | ||
res3 = sql.read_sql_table('test_schema_public_explicit', self.conn, | ||
schema='public') | ||
tm.assert_frame_equal(df, res3) | ||
res4 = sql.read_sql_table('test_schema_other', self.conn, | ||
schema='other') | ||
tm.assert_frame_equal(df, res4) | ||
self.assertRaises(ValueError, sql.read_sql_table, 'test_schema_other', | ||
self.conn, schema='public') | ||
|
||
## different if_exists options | ||
|
||
# create a schema | ||
self.conn.execute("DROP SCHEMA IF EXISTS other CASCADE;") | ||
self.conn.execute("CREATE SCHEMA other;") | ||
|
||
# write dataframe with different if_exists options | ||
df.to_sql('test_schema_other', self.conn, schema='other', index=False) | ||
df.to_sql('test_schema_other', self.conn, schema='other', index=False, | ||
if_exists='replace') | ||
df.to_sql('test_schema_other', self.conn, schema='other', index=False, | ||
if_exists='append') | ||
res = sql.read_sql_table('test_schema_other', self.conn, schema='other') | ||
tm.assert_frame_equal(concat([df, df], ignore_index=True), res) | ||
|
||
## specifying schema in user-provided meta | ||
|
||
engine2 = self.connect() | ||
meta = sqlalchemy.MetaData(engine2, schema='other') | ||
pdsql = sql.PandasSQLAlchemy(engine2, meta=meta) | ||
pdsql.to_sql(df, 'test_schema_other2', index=False) | ||
pdsql.to_sql(df, 'test_schema_other2', index=False, if_exists='replace') | ||
pdsql.to_sql(df, 'test_schema_other2', index=False, if_exists='append') | ||
res1 = sql.read_sql_table('test_schema_other2', self.conn, schema='other') | ||
res2 = pdsql.read_table('test_schema_other2') | ||
tm.assert_frame_equal(res1, res2) | ||
|
||
|
||
#------------------------------------------------------------------------------ | ||
#--- Test Sqlite / MySQL fallback | ||
|
@@ -1295,7 +1350,7 @@ def test_datetime_date(self): | |
tm.assert_frame_equal(res, df.astype(str)) | ||
elif self.flavor == 'mysql': | ||
tm.assert_frame_equal(res, df) | ||
|
||
def test_datetime_time(self): | ||
# test support for datetime.time | ||
raise nose.SkipTest("datetime.time not supported for sqlite fallback") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leave this for now...can't access server (once @cpcloud puts in the conda stuff then easy to change this)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the problem is that the tests will then always fail on 2.6 (the schema keyword is only added in sqlalchemy 0.7.4)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahh ok
only issue is that I can't upload wheels ATM - it will work but will take the build a bit longer - but that's a fast build anyhow