Skip to content

Commit a997356

Browse files
JoergRittingerjorisvandenbossche
authored andcommitted
ENH: add schema support to sql functions
1 parent 1e3da90 commit a997356

File tree

1 file changed

+42
-32
lines changed

1 file changed

+42
-32
lines changed

pandas/io/sql.py

+42-32
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def _is_sqlalchemy_engine(con):
3838
try:
3939
import sqlalchemy
4040
_SQLALCHEMY_INSTALLED = True
41-
41+
4242
from distutils.version import LooseVersion
4343
ver = LooseVersion(sqlalchemy.__version__)
4444
# For sqlalchemy versions < 0.8.2, the BIGINT type is recognized
@@ -47,7 +47,7 @@ def _is_sqlalchemy_engine(con):
4747
if ver < '0.8.2':
4848
from sqlalchemy import BigInteger
4949
from sqlalchemy.ext.compiler import compiles
50-
50+
5151
@compiles(BigInteger, 'sqlite')
5252
def compile_big_int_sqlite(type_, compiler, **kw):
5353
return 'INTEGER'
@@ -145,7 +145,7 @@ def _safe_fetch(cur):
145145
if not isinstance(result, list):
146146
result = list(result)
147147
return result
148-
except Exception as e: # pragma: no cover
148+
except Exception as e: # pragma: no cover
149149
excName = e.__class__.__name__
150150
if excName == 'OperationalError':
151151
return []
@@ -187,7 +187,7 @@ def tquery(sql, con=None, cur=None, retry=True):
187187
con.commit()
188188
except Exception as e:
189189
excName = e.__class__.__name__
190-
if excName == 'OperationalError': # pragma: no cover
190+
if excName == 'OperationalError': # pragma: no cover
191191
print('Failed to commit, may need to restart interpreter')
192192
else:
193193
raise
@@ -199,7 +199,7 @@ def tquery(sql, con=None, cur=None, retry=True):
199199
if result and len(result[0]) == 1:
200200
# python 3 compat
201201
result = list(lzip(*result)[0])
202-
elif result is None: # pragma: no cover
202+
elif result is None: # pragma: no cover
203203
result = []
204204

205205
return result
@@ -253,7 +253,7 @@ def uquery(sql, con=None, cur=None, retry=True, params=None):
253253
#------------------------------------------------------------------------------
254254
#--- Read and write to DataFrames
255255

256-
def read_sql_table(table_name, con, index_col=None, coerce_float=True,
256+
def read_sql_table(table_name, con, schema=None, index_col=None, coerce_float=True,
257257
parse_dates=None, columns=None):
258258
"""Read SQL database table into a DataFrame.
259259
@@ -266,6 +266,7 @@ def read_sql_table(table_name, con, index_col=None, coerce_float=True,
266266
Name of SQL table in database
267267
con : SQLAlchemy engine
268268
Sqlite DBAPI connection mode not supported
269+
schema : Name of SQL schema in database.
269270
index_col : string, optional
270271
Column to set as index
271272
coerce_float : boolean, default True
@@ -300,14 +301,14 @@ def read_sql_table(table_name, con, index_col=None, coerce_float=True,
300301
from sqlalchemy.schema import MetaData
301302
meta = MetaData(con)
302303
try:
303-
meta.reflect(only=[table_name])
304+
meta.reflect(only=[table_name], schema=schema)
304305
except sqlalchemy.exc.InvalidRequestError:
305306
raise ValueError("Table %s not found" % table_name)
306307

307308
pandas_sql = PandasSQLAlchemy(con, meta=meta)
308309
table = pandas_sql.read_table(
309310
table_name, index_col=index_col, coerce_float=coerce_float,
310-
parse_dates=parse_dates, columns=columns)
311+
parse_dates=parse_dates, columns=columns, schema=schema)
311312

312313
if table is not None:
313314
return table
@@ -437,8 +438,8 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,
437438
coerce_float=coerce_float, parse_dates=parse_dates)
438439

439440

440-
def to_sql(frame, name, con, flavor='sqlite', if_exists='fail', index=True,
441-
index_label=None, chunksize=None):
441+
def to_sql(frame, name, con, flavor='sqlite', schema=None, if_exists='fail',
442+
index=True, index_label=None, chunksize=None):
442443
"""
443444
Write records stored in a DataFrame to a SQL database.
444445
@@ -455,6 +456,7 @@ def to_sql(frame, name, con, flavor='sqlite', if_exists='fail', index=True,
455456
The flavor of SQL to use. Ignored when using SQLAlchemy engine.
456457
'mysql' is deprecated and will be removed in future versions, but it
457458
will be further supported through SQLAlchemy engines.
459+
schema : Name of SQL schema in database.
458460
if_exists : {'fail', 'replace', 'append'}, default 'fail'
459461
- fail: If table exists, do nothing.
460462
- replace: If table exists, drop it, recreate it, and insert data.
@@ -481,10 +483,11 @@ def to_sql(frame, name, con, flavor='sqlite', if_exists='fail', index=True,
481483
raise NotImplementedError
482484

483485
pandas_sql.to_sql(frame, name, if_exists=if_exists, index=index,
484-
index_label=index_label, chunksize=chunksize)
486+
index_label=index_label, schema=schema,
487+
chunksize=chunksize)
485488

486489

487-
def has_table(table_name, con, flavor='sqlite'):
490+
def has_table(table_name, con, flavor='sqlite', schema=None):
488491
"""
489492
Check if DataBase has named table.
490493
@@ -500,13 +503,14 @@ def has_table(table_name, con, flavor='sqlite'):
500503
The flavor of SQL to use. Ignored when using SQLAlchemy engine.
501504
'mysql' is deprecated and will be removed in future versions, but it
502505
will be further supported through SQLAlchemy engines.
506+
schema : Name of SQL schema in database.
503507
504508
Returns
505509
-------
506510
boolean
507511
"""
508512
pandas_sql = pandasSQL_builder(con, flavor=flavor)
509-
return pandas_sql.has_table(table_name)
513+
return pandas_sql.has_table(table_name, schema=schema)
510514

511515
table_exists = has_table
512516

@@ -540,24 +544,26 @@ class PandasSQLTable(PandasObject):
540544
"""
541545
# TODO: support for multiIndex
542546
def __init__(self, name, pandas_sql_engine, frame=None, index=True,
543-
if_exists='fail', prefix='pandas', index_label=None):
547+
if_exists='fail', prefix='pandas', index_label=None,
548+
schema=None):
544549
self.name = name
545550
self.pd_sql = pandas_sql_engine
546551
self.prefix = prefix
547552
self.frame = frame
548553
self.index = self._index_name(index, index_label)
554+
self.schema = schema
549555

550556
if frame is not None:
551557
# We want to write a frame
552-
if self.pd_sql.has_table(self.name):
558+
if self.pd_sql.has_table(self.name, self.schema):
553559
if if_exists == 'fail':
554560
raise ValueError("Table '%s' already exists." % name)
555561
elif if_exists == 'replace':
556-
self.pd_sql.drop_table(self.name)
562+
self.pd_sql.drop_table(self.name, self.schema)
557563
self.table = self._create_table_statement()
558564
self.create()
559565
elif if_exists == 'append':
560-
self.table = self.pd_sql.get_table(self.name)
566+
self.table = self.pd_sql.get_table(self.name, self.schema)
561567
if self.table is None:
562568
self.table = self._create_table_statement()
563569
else:
@@ -568,13 +574,13 @@ def __init__(self, name, pandas_sql_engine, frame=None, index=True,
568574
self.create()
569575
else:
570576
# no data provided, read-only mode
571-
self.table = self.pd_sql.get_table(self.name)
577+
self.table = self.pd_sql.get_table(self.name, self.schema)
572578

573579
if self.table is None:
574580
raise ValueError("Could not init table '%s'" % name)
575581

576582
def exists(self):
577-
return self.pd_sql.has_table(self.name)
583+
return self.pd_sql.has_table(self.name, self.schema)
578584

579585
def sql_schema(self):
580586
from sqlalchemy.schema import CreateTable
@@ -709,7 +715,7 @@ def _create_table_statement(self):
709715
columns = [Column(name, typ)
710716
for name, typ in column_names_and_types]
711717

712-
return Table(self.name, self.pd_sql.meta, *columns)
718+
return Table(self.name, self.pd_sql.meta, *columns, schema=self.schema)
713719

714720
def _harmonize_columns(self, parse_dates=None):
715721
""" Make a data_frame's column type align with an sql_table
@@ -843,9 +849,10 @@ def execute(self, *args, **kwargs):
843849
return self.engine.execute(*args, **kwargs)
844850

845851
def read_table(self, table_name, index_col=None, coerce_float=True,
846-
parse_dates=None, columns=None):
852+
parse_dates=None, columns=None, schema=None):
847853

848-
table = PandasSQLTable(table_name, self, index=index_col)
854+
table = PandasSQLTable(
855+
table_name, self, index=index_col, schema=schema)
849856
return table.read(coerce_float=coerce_float,
850857
parse_dates=parse_dates, columns=columns)
851858

@@ -868,26 +875,29 @@ def read_sql(self, sql, index_col=None, coerce_float=True,
868875
return data_frame
869876

870877
def to_sql(self, frame, name, if_exists='fail', index=True,
871-
index_label=None, chunksize=None):
878+
index_label=None, schema=None, chunksize=None):
872879
table = PandasSQLTable(
873880
name, self, frame=frame, index=index, if_exists=if_exists,
874-
index_label=index_label)
881+
index_label=index_label, schema=schema)
875882
table.insert(chunksize)
876883

877884
@property
878885
def tables(self):
879886
return self.meta.tables
880887

881-
def has_table(self, name):
882-
return self.engine.has_table(name)
888+
def has_table(self, name, schema=None):
889+
return self.engine.has_table(name, schema)
883890

884-
def get_table(self, table_name):
885-
return self.meta.tables.get(table_name)
891+
def get_table(self, table_name, schema=None):
892+
if schema:
893+
return self.meta.tables.get('.'.join([schema, table_name]))
894+
else:
895+
return self.meta.tables.get(table_name)
886896

887-
def drop_table(self, table_name):
888-
if self.engine.has_table(table_name):
889-
self.meta.reflect(only=[table_name])
890-
self.get_table(table_name).drop()
897+
def drop_table(self, table_name, schema=None):
898+
if self.engine.has_table(table_name, schema):
899+
self.meta.reflect(only=[table_name], schema=schema)
900+
self.get_table(table_name, schema).drop()
891901
self.meta.clear()
892902

893903
def _create_sql_schema(self, frame, table_name):

0 commit comments

Comments
 (0)