@@ -38,7 +38,7 @@ def _is_sqlalchemy_engine(con):
38
38
try :
39
39
import sqlalchemy
40
40
_SQLALCHEMY_INSTALLED = True
41
-
41
+
42
42
from distutils .version import LooseVersion
43
43
ver = LooseVersion (sqlalchemy .__version__ )
44
44
# For sqlalchemy versions < 0.8.2, the BIGINT type is recognized
@@ -47,7 +47,7 @@ def _is_sqlalchemy_engine(con):
47
47
if ver < '0.8.2' :
48
48
from sqlalchemy import BigInteger
49
49
from sqlalchemy .ext .compiler import compiles
50
-
50
+
51
51
@compiles (BigInteger , 'sqlite' )
52
52
def compile_big_int_sqlite (type_ , compiler , ** kw ):
53
53
return 'INTEGER'
@@ -145,7 +145,7 @@ def _safe_fetch(cur):
145
145
if not isinstance (result , list ):
146
146
result = list (result )
147
147
return result
148
- except Exception as e : # pragma: no cover
148
+ except Exception as e : # pragma: no cover
149
149
excName = e .__class__ .__name__
150
150
if excName == 'OperationalError' :
151
151
return []
@@ -187,7 +187,7 @@ def tquery(sql, con=None, cur=None, retry=True):
187
187
con .commit ()
188
188
except Exception as e :
189
189
excName = e .__class__ .__name__
190
- if excName == 'OperationalError' : # pragma: no cover
190
+ if excName == 'OperationalError' : # pragma: no cover
191
191
print ('Failed to commit, may need to restart interpreter' )
192
192
else :
193
193
raise
@@ -199,7 +199,7 @@ def tquery(sql, con=None, cur=None, retry=True):
199
199
if result and len (result [0 ]) == 1 :
200
200
# python 3 compat
201
201
result = list (lzip (* result )[0 ])
202
- elif result is None : # pragma: no cover
202
+ elif result is None : # pragma: no cover
203
203
result = []
204
204
205
205
return result
@@ -253,8 +253,8 @@ def uquery(sql, con=None, cur=None, retry=True, params=None):
253
253
#------------------------------------------------------------------------------
254
254
#--- Read and write to DataFrames
255
255
256
- def read_sql_table (table_name , con , index_col = None , coerce_float = True ,
257
- parse_dates = None , columns = None ):
256
+ def read_sql_table (table_name , con , schema = None , index_col = None ,
257
+ coerce_float = True , parse_dates = None , columns = None ):
258
258
"""Read SQL database table into a DataFrame.
259
259
260
260
Given a table name and an SQLAlchemy engine, returns a DataFrame.
@@ -266,6 +266,9 @@ def read_sql_table(table_name, con, index_col=None, coerce_float=True,
266
266
Name of SQL table in database
267
267
con : SQLAlchemy engine
268
268
Sqlite DBAPI connection mode not supported
269
+ schema : string, default None
270
+ Name of SQL schema in database to query (if database flavor supports this).
271
+ If None, use default schema (default).
269
272
index_col : string, optional
270
273
Column to set as index
271
274
coerce_float : boolean, default True
@@ -298,7 +301,7 @@ def read_sql_table(table_name, con, index_col=None, coerce_float=True,
298
301
"SQLAlchemy engines." )
299
302
import sqlalchemy
300
303
from sqlalchemy .schema import MetaData
301
- meta = MetaData (con )
304
+ meta = MetaData (con , schema = schema )
302
305
try :
303
306
meta .reflect (only = [table_name ])
304
307
except sqlalchemy .exc .InvalidRequestError :
@@ -437,8 +440,8 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,
437
440
coerce_float = coerce_float , parse_dates = parse_dates )
438
441
439
442
440
- def to_sql (frame , name , con , flavor = 'sqlite' , if_exists = 'fail' , index = True ,
441
- index_label = None , chunksize = None ):
443
+ def to_sql (frame , name , con , flavor = 'sqlite' , schema = None , if_exists = 'fail' ,
444
+ index = True , index_label = None , chunksize = None ):
442
445
"""
443
446
Write records stored in a DataFrame to a SQL database.
444
447
@@ -455,6 +458,9 @@ def to_sql(frame, name, con, flavor='sqlite', if_exists='fail', index=True,
455
458
The flavor of SQL to use. Ignored when using SQLAlchemy engine.
456
459
'mysql' is deprecated and will be removed in future versions, but it
457
460
will be further supported through SQLAlchemy engines.
461
+ schema : string, default None
462
+ Name of SQL schema in database to write to (if database flavor supports
463
+ this). If None, use default schema (default).
458
464
if_exists : {'fail', 'replace', 'append'}, default 'fail'
459
465
- fail: If table exists, do nothing.
460
466
- replace: If table exists, drop it, recreate it, and insert data.
@@ -473,18 +479,19 @@ def to_sql(frame, name, con, flavor='sqlite', if_exists='fail', index=True,
473
479
if if_exists not in ('fail' , 'replace' , 'append' ):
474
480
raise ValueError ("'{0}' is not valid for if_exists" .format (if_exists ))
475
481
476
- pandas_sql = pandasSQL_builder (con , flavor = flavor )
482
+ pandas_sql = pandasSQL_builder (con , schema = schema , flavor = flavor )
477
483
478
484
if isinstance (frame , Series ):
479
485
frame = frame .to_frame ()
480
486
elif not isinstance (frame , DataFrame ):
481
487
raise NotImplementedError
482
488
483
489
pandas_sql .to_sql (frame , name , if_exists = if_exists , index = index ,
484
- index_label = index_label , chunksize = chunksize )
490
+ index_label = index_label , schema = schema ,
491
+ chunksize = chunksize )
485
492
486
493
487
- def has_table (table_name , con , flavor = 'sqlite' ):
494
+ def has_table (table_name , con , flavor = 'sqlite' , schema = None ):
488
495
"""
489
496
Check if DataBase has named table.
490
497
@@ -500,12 +507,15 @@ def has_table(table_name, con, flavor='sqlite'):
500
507
The flavor of SQL to use. Ignored when using SQLAlchemy engine.
501
508
'mysql' is deprecated and will be removed in future versions, but it
502
509
will be further supported through SQLAlchemy engines.
510
+ schema : string, default None
511
+ Name of SQL schema in database to write to (if database flavor supports
512
+ this). If None, use default schema (default).
503
513
504
514
Returns
505
515
-------
506
516
boolean
507
517
"""
508
- pandas_sql = pandasSQL_builder (con , flavor = flavor )
518
+ pandas_sql = pandasSQL_builder (con , flavor = flavor , schema = schema )
509
519
return pandas_sql .has_table (table_name )
510
520
511
521
table_exists = has_table
@@ -515,15 +525,15 @@ def has_table(table_name, con, flavor='sqlite'):
515
525
"and will be removed in future versions. "
516
526
"MySQL will be further supported with SQLAlchemy engines." )
517
527
518
- def pandasSQL_builder (con , flavor = None , meta = None , is_cursor = False ):
528
+ def pandasSQL_builder (con , flavor = None , schema = None , meta = None , is_cursor = False ):
519
529
"""
520
530
Convenience function to return the correct PandasSQL subclass based on the
521
531
provided parameters
522
532
"""
523
533
# When support for DBAPI connections is removed,
524
534
# is_cursor should not be necessary.
525
535
if _is_sqlalchemy_engine (con ):
526
- return PandasSQLAlchemy (con , meta = meta )
536
+ return PandasSQLAlchemy (con , schema = schema , meta = meta )
527
537
else :
528
538
if flavor == 'mysql' :
529
539
warnings .warn (_MYSQL_WARNING , FutureWarning )
@@ -540,24 +550,26 @@ class PandasSQLTable(PandasObject):
540
550
"""
541
551
# TODO: support for multiIndex
542
552
def __init__ (self , name , pandas_sql_engine , frame = None , index = True ,
543
- if_exists = 'fail' , prefix = 'pandas' , index_label = None ):
553
+ if_exists = 'fail' , prefix = 'pandas' , index_label = None ,
554
+ schema = None ):
544
555
self .name = name
545
556
self .pd_sql = pandas_sql_engine
546
557
self .prefix = prefix
547
558
self .frame = frame
548
559
self .index = self ._index_name (index , index_label )
560
+ self .schema = schema
549
561
550
562
if frame is not None :
551
563
# We want to write a frame
552
- if self .pd_sql .has_table (self .name ):
564
+ if self .pd_sql .has_table (self .name , self . schema ):
553
565
if if_exists == 'fail' :
554
566
raise ValueError ("Table '%s' already exists." % name )
555
567
elif if_exists == 'replace' :
556
- self .pd_sql .drop_table (self .name )
568
+ self .pd_sql .drop_table (self .name , self . schema )
557
569
self .table = self ._create_table_statement ()
558
570
self .create ()
559
571
elif if_exists == 'append' :
560
- self .table = self .pd_sql .get_table (self .name )
572
+ self .table = self .pd_sql .get_table (self .name , self . schema )
561
573
if self .table is None :
562
574
self .table = self ._create_table_statement ()
563
575
else :
@@ -568,13 +580,13 @@ def __init__(self, name, pandas_sql_engine, frame=None, index=True,
568
580
self .create ()
569
581
else :
570
582
# no data provided, read-only mode
571
- self .table = self .pd_sql .get_table (self .name )
583
+ self .table = self .pd_sql .get_table (self .name , self . schema )
572
584
573
585
if self .table is None :
574
586
raise ValueError ("Could not init table '%s'" % name )
575
587
576
588
def exists (self ):
577
- return self .pd_sql .has_table (self .name )
589
+ return self .pd_sql .has_table (self .name , self . schema )
578
590
579
591
def sql_schema (self ):
580
592
from sqlalchemy .schema import CreateTable
@@ -709,7 +721,7 @@ def _create_table_statement(self):
709
721
columns = [Column (name , typ )
710
722
for name , typ in column_names_and_types ]
711
723
712
- return Table (self .name , self .pd_sql .meta , * columns )
724
+ return Table (self .name , self .pd_sql .meta , * columns , schema = self . schema )
713
725
714
726
def _harmonize_columns (self , parse_dates = None ):
715
727
""" Make a data_frame's column type align with an sql_table
@@ -830,11 +842,11 @@ class PandasSQLAlchemy(PandasSQL):
830
842
using SQLAlchemy to handle DataBase abstraction
831
843
"""
832
844
833
- def __init__ (self , engine , meta = None ):
845
+ def __init__ (self , engine , schema = None , meta = None ):
834
846
self .engine = engine
835
847
if not meta :
836
848
from sqlalchemy .schema import MetaData
837
- meta = MetaData (self .engine )
849
+ meta = MetaData (self .engine , schema = schema )
838
850
839
851
self .meta = meta
840
852
@@ -843,9 +855,10 @@ def execute(self, *args, **kwargs):
843
855
return self .engine .execute (* args , ** kwargs )
844
856
845
857
def read_table (self , table_name , index_col = None , coerce_float = True ,
846
- parse_dates = None , columns = None ):
858
+ parse_dates = None , columns = None , schema = None ):
847
859
848
- table = PandasSQLTable (table_name , self , index = index_col )
860
+ table = PandasSQLTable (
861
+ table_name , self , index = index_col , schema = schema )
849
862
return table .read (coerce_float = coerce_float ,
850
863
parse_dates = parse_dates , columns = columns )
851
864
@@ -868,26 +881,31 @@ def read_sql(self, sql, index_col=None, coerce_float=True,
868
881
return data_frame
869
882
870
883
def to_sql (self , frame , name , if_exists = 'fail' , index = True ,
871
- index_label = None , chunksize = None ):
884
+ index_label = None , schema = None , chunksize = None ):
872
885
table = PandasSQLTable (
873
886
name , self , frame = frame , index = index , if_exists = if_exists ,
874
- index_label = index_label )
887
+ index_label = index_label , schema = schema )
875
888
table .insert (chunksize )
876
889
877
890
@property
878
891
def tables (self ):
879
892
return self .meta .tables
880
893
881
- def has_table (self , name ):
882
- return self .engine .has_table (name )
894
+ def has_table (self , name , schema = None ):
895
+ return self .engine .has_table (name , schema or self . meta . schema )
883
896
884
- def get_table (self , table_name ):
885
- return self .meta .tables .get (table_name )
897
+ def get_table (self , table_name , schema = None ):
898
+ schema = schema or self .meta .schema
899
+ if schema :
900
+ return self .meta .tables .get ('.' .join ([schema , table_name ]))
901
+ else :
902
+ return self .meta .tables .get (table_name )
886
903
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 ()
904
+ def drop_table (self , table_name , schema = None ):
905
+ schema = schema or self .meta .schema
906
+ if self .engine .has_table (table_name , schema ):
907
+ self .meta .reflect (only = [table_name ], schema = schema )
908
+ self .get_table (table_name , schema ).drop ()
891
909
self .meta .clear ()
892
910
893
911
def _create_sql_schema (self , frame , table_name ):
@@ -1113,7 +1131,7 @@ def _fetchall_as_list(self, cur):
1113
1131
return result
1114
1132
1115
1133
def to_sql (self , frame , name , if_exists = 'fail' , index = True ,
1116
- index_label = None , chunksize = None ):
1134
+ index_label = None , schema = None , chunksize = None ):
1117
1135
"""
1118
1136
Write records stored in a DataFrame to a SQL database.
1119
1137
@@ -1133,7 +1151,7 @@ def to_sql(self, frame, name, if_exists='fail', index=True,
1133
1151
index_label = index_label )
1134
1152
table .insert (chunksize )
1135
1153
1136
- def has_table (self , name ):
1154
+ def has_table (self , name , schema = None ):
1137
1155
flavor_map = {
1138
1156
'sqlite' : ("SELECT name FROM sqlite_master "
1139
1157
"WHERE type='table' AND name='%s';" ) % name ,
@@ -1142,10 +1160,10 @@ def has_table(self, name):
1142
1160
1143
1161
return len (self .execute (query ).fetchall ()) > 0
1144
1162
1145
- def get_table (self , table_name ):
1163
+ def get_table (self , table_name , schema = None ):
1146
1164
return None # not supported in Legacy mode
1147
1165
1148
- def drop_table (self , name ):
1166
+ def drop_table (self , name , schema = None ):
1149
1167
drop_sql = "DROP TABLE %s" % name
1150
1168
self .execute (drop_sql )
1151
1169
0 commit comments