Skip to content

Commit 18bd0d6

Browse files
ENH/TST SQL: add multi-index support to read_table
1 parent 0a26065 commit 18bd0d6

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

pandas/io/sql.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ def read_table(table_name, con, meta=None, index_col=None, coerce_float=True,
310310
Legacy mode not supported
311311
meta : SQLAlchemy meta, optional
312312
If omitted MetaData is reflected from engine
313-
index_col : string, optional
314-
Column to set as index
313+
index_col : string or sequence of strings, optional
314+
Column(s) to set as index.
315315
coerce_float : boolean, default True
316316
Attempt to convert values to non-string, non-numeric objects (like
317317
decimal.Decimal) to floating point. Can result in loss of Precision.
@@ -324,7 +324,7 @@ def read_table(table_name, con, meta=None, index_col=None, coerce_float=True,
324324
to the keyword arguments of :func:`pandas.to_datetime`
325325
Especially useful with databases without native Datetime support,
326326
such as SQLite
327-
columns : list
327+
columns : list, optional
328328
List of column names to select from sql table
329329
330330
Returns
@@ -466,7 +466,7 @@ def read(self, coerce_float=True, parse_dates=None, columns=None):
466466
from sqlalchemy import select
467467
cols = [self.table.c[n] for n in columns]
468468
if self.index is not None:
469-
cols.insert(0, self.table.c[self.index])
469+
[cols.insert(0, self.table.c[idx]) for idx in self.index[::-1]]
470470
sql_select = select(cols)
471471
else:
472472
sql_select = self.table.select()
@@ -483,14 +483,10 @@ def read(self, coerce_float=True, parse_dates=None, columns=None):
483483
if self.index is not None:
484484
self.frame.set_index(self.index, inplace=True)
485485

486-
# Assume if the index in prefix_index format, we gave it a name
487-
# and should return it nameless
488-
if self.index == self.prefix + '_index':
489-
self.frame.index.name = None
490-
491486
return self.frame
492487

493488
def _index_name(self, index, index_label):
489+
# for writing: index=True to include index in sql table
494490
if index is True:
495491
nlevels = self.frame.index.nlevels
496492
# if index_label is specified, set this as index name(s)
@@ -510,7 +506,10 @@ def _index_name(self, index, index_label):
510506
return [l if l is not None else "level_{0}".format(i)
511507
for i, l in enumerate(self.frame.index.names)]
512508

509+
# for reading: index=(list of) string to specify column to set as index
513510
elif isinstance(index, string_types):
511+
return [index]
512+
elif isinstance(index, list):
514513
return index
515514
else:
516515
return None

pandas/io/tests/test_sql.py

+19
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,25 @@ def test_read_table_columns(self):
549549
self.assertEqual(result.columns.tolist(), cols,
550550
"Columns not correctly selected")
551551

552+
def test_read_table_index_col(self):
553+
# test columns argument in read_table
554+
sql.to_sql(self.test_frame1, 'test_frame', self.conn)
555+
556+
result = sql.read_table('test_frame', self.conn, index_col="index")
557+
self.assertEqual(result.index.names, ["index"],
558+
"index_col not correctly set")
559+
560+
result = sql.read_table('test_frame', self.conn, index_col=["A", "B"])
561+
self.assertEqual(result.index.names, ["A", "B"],
562+
"index_col not correctly set")
563+
564+
result = sql.read_table('test_frame', self.conn, index_col=["A", "B"],
565+
columns=["C", "D"])
566+
self.assertEqual(result.index.names, ["A", "B"],
567+
"index_col not correctly set")
568+
self.assertEqual(result.columns.tolist(), ["C", "D"],
569+
"columns not set correctly whith index_col")
570+
552571

553572
class TestSQLLegacyApi(_TestSQLApi):
554573

0 commit comments

Comments
 (0)