Skip to content

Commit c875d87

Browse files
committed
BUG: enable multivalues insert
1 parent 569bc7a commit c875d87

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

doc/source/whatsnew/v0.23.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ Other Enhancements
323323

324324
- ``IntervalIndex.astype`` now supports conversions between subtypes when passed an ``IntervalDtype`` (:issue:`19197`)
325325
- :class:`IntervalIndex` and its associated constructor methods (``from_arrays``, ``from_breaks``, ``from_tuples``) have gained a ``dtype`` parameter (:issue:`19262`)
326+
- :func:`pd.io.sql.to_sql` will now perform a multivalue insert if the underlying connection supports this rather than inserting line by line
326327

327328
.. _whatsnew_0230.api_breaking:
328329

pandas/io/sql.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,15 @@ def create(self):
572572
else:
573573
self._execute_create()
574574

575-
def insert_statement(self):
576-
return self.table.insert()
575+
def insert_statement(self, data, conn):
576+
"""
577+
Generate tuple of SQLAlchemy statement and any arguments to be executed
578+
by connection (via `_execute_insert`) to insert data into this table.
579+
"""
580+
dialect = getattr(conn, 'dialect', None)
581+
if dialect and getattr(dialect, 'supports_multivalues_insert', False):
582+
return (self.table.insert(data),)
583+
return (self.table.insert(), data)
577584

578585
def insert_data(self):
579586
if self.index is not None:
@@ -612,8 +619,9 @@ def insert_data(self):
612619
return column_names, data_list
613620

614621
def _execute_insert(self, conn, keys, data_iter):
622+
"""Insert data into this table with database connection"""
615623
data = [{k: v for k, v in zip(keys, row)} for row in data_iter]
616-
conn.execute(self.insert_statement(), data)
624+
conn.execute(*self.insert_statement(data, conn))
617625

618626
def insert(self, chunksize=None):
619627
keys, data_list = self.insert_data()

pandas/tests/io/test_sql.py

+23
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,29 @@ class Temporary(Base):
16651665

16661666
tm.assert_frame_equal(df, expected)
16671667

1668+
def test_insert_multivalues(self):
1669+
# issues addressed
1670+
# https://github.com/pandas-dev/pandas/issues/14315
1671+
# https://github.com/pandas-dev/pandas/issues/8953
1672+
1673+
db = sql.SQLDatabase(self.conn)
1674+
df = DataFrame({'A': [1, 0, 0], 'B': [1.1, 0.2, 4.3]})
1675+
table = sql.SQLTable("test_table", db, frame=df)
1676+
data = [
1677+
{'A': 1, 'B': 0.46},
1678+
{'A': 0, 'B': -2.06}
1679+
]
1680+
statement = table.insert_statement(data, conn=self.conn)[0]
1681+
dialect = getattr(self.conn, 'dialect', None)
1682+
if dialect and getattr(dialect, 'supports_multivalues_insert', False):
1683+
assert statement.parameters == data, (
1684+
'insert statement should be multivalues'
1685+
)
1686+
else:
1687+
assert statement.parameters is None, (
1688+
'insert statement should not be multivalues'
1689+
)
1690+
16681691

16691692
class _TestSQLAlchemyConn(_EngineToConnMixin, _TestSQLAlchemy):
16701693

0 commit comments

Comments
 (0)