@@ -512,6 +512,7 @@ def read_sql(
512
512
>>> df = pd.DataFrame(data=[[0, '10/11/12'], [1, '12/11/10']],
513
513
... columns=['int_column', 'date_column'])
514
514
>>> df.to_sql('test_data', conn)
515
+ 2
515
516
516
517
>>> pd.read_sql('SELECT int_column, date_column FROM test_data', conn)
517
518
int_column date_column
@@ -611,7 +612,7 @@ def to_sql(
611
612
method : str | None = None ,
612
613
engine : str = "auto" ,
613
614
** engine_kwargs ,
614
- ) -> None :
615
+ ) -> int | None :
615
616
"""
616
617
Write records stored in a DataFrame to a SQL database.
617
618
@@ -650,8 +651,8 @@ def to_sql(
650
651
Controls the SQL insertion clause used:
651
652
652
653
- None : Uses standard SQL ``INSERT`` clause (one per row).
653
- - 'multi': Pass multiple values in a single ``INSERT`` clause.
654
- - callable with signature ``(pd_table, conn, keys, data_iter)``.
654
+ - `` 'multi'`` : Pass multiple values in a single ``INSERT`` clause.
655
+ - callable with signature ``(pd_table, conn, keys, data_iter) -> int | None ``.
655
656
656
657
Details and a sample callable implementation can be found in the
657
658
section :ref:`insert method <io.sql.method>`.
@@ -664,7 +665,23 @@ def to_sql(
664
665
665
666
**engine_kwargs
666
667
Any additional kwargs are passed to the engine.
667
- """
668
+
669
+ Returns
670
+ -------
671
+ None or int
672
+ Number of rows affected by to_sql. None is returned if the callable
673
+ passed into ``method`` does not return the number of rows.
674
+
675
+ .. versionadded:: 1.4.0
676
+
677
+ Notes
678
+ -----
679
+ The returned rows affected is the sum of the ``rowcount`` attribute of ``sqlite3.Cursor``
680
+ or SQLAlchemy connectable. The returned value may not reflect the exact number of written
681
+ rows as stipulated in the
682
+ `sqlite3 <https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.rowcount>`__ or
683
+ `SQLAlchemy <https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.BaseCursorResult.rowcount>`__
684
+ """ # noqa:E501
668
685
if if_exists not in ("fail" , "replace" , "append" ):
669
686
raise ValueError (f"'{ if_exists } ' is not valid for if_exists" )
670
687
@@ -677,7 +694,7 @@ def to_sql(
677
694
"'frame' argument should be either a Series or a DataFrame"
678
695
)
679
696
680
- pandas_sql .to_sql (
697
+ return pandas_sql .to_sql (
681
698
frame ,
682
699
name ,
683
700
if_exists = if_exists ,
@@ -817,7 +834,7 @@ def create(self):
817
834
else :
818
835
self ._execute_create ()
819
836
820
- def _execute_insert (self , conn , keys : list [str ], data_iter ):
837
+ def _execute_insert (self , conn , keys : list [str ], data_iter ) -> int :
821
838
"""
822
839
Execute SQL statement inserting data
823
840
@@ -830,9 +847,10 @@ def _execute_insert(self, conn, keys: list[str], data_iter):
830
847
Each item contains a list of values to be inserted
831
848
"""
832
849
data = [dict (zip (keys , row )) for row in data_iter ]
833
- conn .execute (self .table .insert (), data )
850
+ result = conn .execute (self .table .insert (), data )
851
+ return result .rowcount
834
852
835
- def _execute_insert_multi (self , conn , keys : list [str ], data_iter ):
853
+ def _execute_insert_multi (self , conn , keys : list [str ], data_iter ) -> int :
836
854
"""
837
855
Alternative to _execute_insert for DBs support multivalue INSERT.
838
856
@@ -845,7 +863,8 @@ def _execute_insert_multi(self, conn, keys: list[str], data_iter):
845
863
846
864
data = [dict (zip (keys , row )) for row in data_iter ]
847
865
stmt = insert (self .table ).values (data )
848
- conn .execute (stmt )
866
+ result = conn .execute (stmt )
867
+ return result .rowcount
849
868
850
869
def insert_data (self ):
851
870
if self .index is not None :
@@ -885,7 +904,9 @@ def insert_data(self):
885
904
886
905
return column_names , data_list
887
906
888
- def insert (self , chunksize : int | None = None , method : str | None = None ):
907
+ def insert (
908
+ self , chunksize : int | None = None , method : str | None = None
909
+ ) -> int | None :
889
910
890
911
# set insert method
891
912
if method is None :
@@ -902,15 +923,15 @@ def insert(self, chunksize: int | None = None, method: str | None = None):
902
923
nrows = len (self .frame )
903
924
904
925
if nrows == 0 :
905
- return
926
+ return 0
906
927
907
928
if chunksize is None :
908
929
chunksize = nrows
909
930
elif chunksize == 0 :
910
931
raise ValueError ("chunksize argument should be non-zero" )
911
932
912
933
chunks = (nrows // chunksize ) + 1
913
-
934
+ total_inserted = 0
914
935
with self .pd_sql .run_transaction () as conn :
915
936
for i in range (chunks ):
916
937
start_i = i * chunksize
@@ -919,7 +940,12 @@ def insert(self, chunksize: int | None = None, method: str | None = None):
919
940
break
920
941
921
942
chunk_iter = zip (* (arr [start_i :end_i ] for arr in data_list ))
922
- exec_insert (conn , keys , chunk_iter )
943
+ num_inserted = exec_insert (conn , keys , chunk_iter )
944
+ if num_inserted is None :
945
+ total_inserted = None
946
+ else :
947
+ total_inserted += num_inserted
948
+ return total_inserted
923
949
924
950
def _query_iterator (
925
951
self ,
@@ -1239,7 +1265,7 @@ def to_sql(
1239
1265
chunksize = None ,
1240
1266
dtype : DtypeArg | None = None ,
1241
1267
method = None ,
1242
- ):
1268
+ ) -> int | None :
1243
1269
raise ValueError (
1244
1270
"PandasSQL must be created with an SQLAlchemy "
1245
1271
"connectable or sqlite connection"
@@ -1258,7 +1284,7 @@ def insert_records(
1258
1284
chunksize = None ,
1259
1285
method = None ,
1260
1286
** engine_kwargs ,
1261
- ):
1287
+ ) -> int | None :
1262
1288
"""
1263
1289
Inserts data into already-prepared table
1264
1290
"""
@@ -1282,11 +1308,11 @@ def insert_records(
1282
1308
chunksize = None ,
1283
1309
method = None ,
1284
1310
** engine_kwargs ,
1285
- ):
1311
+ ) -> int | None :
1286
1312
from sqlalchemy import exc
1287
1313
1288
1314
try :
1289
- table .insert (chunksize = chunksize , method = method )
1315
+ return table .insert (chunksize = chunksize , method = method )
1290
1316
except exc .SQLAlchemyError as err :
1291
1317
# GH34431
1292
1318
# https://stackoverflow.com/a/67358288/6067848
@@ -1643,7 +1669,7 @@ def to_sql(
1643
1669
method = None ,
1644
1670
engine = "auto" ,
1645
1671
** engine_kwargs ,
1646
- ):
1672
+ ) -> int | None :
1647
1673
"""
1648
1674
Write records stored in a DataFrame to a SQL database.
1649
1675
@@ -1704,7 +1730,7 @@ def to_sql(
1704
1730
dtype = dtype ,
1705
1731
)
1706
1732
1707
- sql_engine .insert_records (
1733
+ total_inserted = sql_engine .insert_records (
1708
1734
table = table ,
1709
1735
con = self .connectable ,
1710
1736
frame = frame ,
@@ -1717,6 +1743,7 @@ def to_sql(
1717
1743
)
1718
1744
1719
1745
self .check_case_sensitive (name = name , schema = schema )
1746
+ return total_inserted
1720
1747
1721
1748
@property
1722
1749
def tables (self ):
@@ -1859,14 +1886,16 @@ def insert_statement(self, *, num_rows: int):
1859
1886
)
1860
1887
return insert_statement
1861
1888
1862
- def _execute_insert (self , conn , keys , data_iter ):
1889
+ def _execute_insert (self , conn , keys , data_iter ) -> int :
1863
1890
data_list = list (data_iter )
1864
1891
conn .executemany (self .insert_statement (num_rows = 1 ), data_list )
1892
+ return conn .rowcount
1865
1893
1866
- def _execute_insert_multi (self , conn , keys , data_iter ):
1894
+ def _execute_insert_multi (self , conn , keys , data_iter ) -> int :
1867
1895
data_list = list (data_iter )
1868
1896
flattened_data = [x for row in data_list for x in row ]
1869
1897
conn .execute (self .insert_statement (num_rows = len (data_list )), flattened_data )
1898
+ return conn .rowcount
1870
1899
1871
1900
def _create_table_setup (self ):
1872
1901
"""
@@ -2088,7 +2117,7 @@ def to_sql(
2088
2117
dtype : DtypeArg | None = None ,
2089
2118
method = None ,
2090
2119
** kwargs ,
2091
- ):
2120
+ ) -> int | None :
2092
2121
"""
2093
2122
Write records stored in a DataFrame to a SQL database.
2094
2123
@@ -2153,7 +2182,7 @@ def to_sql(
2153
2182
dtype = dtype ,
2154
2183
)
2155
2184
table .create ()
2156
- table .insert (chunksize , method )
2185
+ return table .insert (chunksize , method )
2157
2186
2158
2187
def has_table (self , name : str , schema : str | None = None ):
2159
2188
0 commit comments