76
76
77
77
from sqlalchemy import Table
78
78
from sqlalchemy .sql .expression import (
79
+ Delete ,
79
80
Select ,
80
81
TextClause ,
81
82
)
@@ -738,7 +739,7 @@ def to_sql(
738
739
name : str ,
739
740
con ,
740
741
schema : str | None = None ,
741
- if_exists : Literal ["fail" , "replace" , "append" ] = "fail" ,
742
+ if_exists : Literal ["fail" , "replace" , "append" , "delete_rows" ] = "fail" ,
742
743
index : bool = True ,
743
744
index_label : IndexLabel | None = None ,
744
745
chunksize : int | None = None ,
@@ -750,6 +751,12 @@ def to_sql(
750
751
"""
751
752
Write records stored in a DataFrame to a SQL database.
752
753
754
+ .. warning::
755
+ The pandas library does not attempt to sanitize inputs provided via a to_sql call.
756
+ Please refer to the documentation for the underlying database driver to see if it
757
+ will properly prevent injection, or alternatively be advised of a security risk when
758
+ executing arbitrary commands in a to_sql call.
759
+
753
760
Parameters
754
761
----------
755
762
frame : DataFrame, Series
@@ -764,10 +771,11 @@ def to_sql(
764
771
schema : str, optional
765
772
Name of SQL schema in database to write to (if database flavor
766
773
supports this). If None, use default schema (default).
767
- if_exists : {'fail', 'replace', 'append'}, default 'fail'
774
+ if_exists : {'fail', 'replace', 'append', 'delete_rows' }, default 'fail'
768
775
- fail: If table exists, do nothing.
769
776
- replace: If table exists, drop it, recreate it, and insert data.
770
777
- append: If table exists, insert data. Create if does not exist.
778
+ - delete_rows: If a table exists, delete all records and insert data.
771
779
index : bool, default True
772
780
Write DataFrame index as a column.
773
781
index_label : str or sequence, optional
@@ -818,7 +826,7 @@ def to_sql(
818
826
`sqlite3 <https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.rowcount>`__ or
819
827
`SQLAlchemy <https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.BaseCursorResult.rowcount>`__
820
828
""" # noqa: E501
821
- if if_exists not in ("fail" , "replace" , "append" ):
829
+ if if_exists not in ("fail" , "replace" , "append" , "delete_rows" ):
822
830
raise ValueError (f"'{ if_exists } ' is not valid for if_exists" )
823
831
824
832
if isinstance (frame , Series ):
@@ -926,7 +934,7 @@ def __init__(
926
934
pandas_sql_engine ,
927
935
frame = None ,
928
936
index : bool | str | list [str ] | None = True ,
929
- if_exists : Literal ["fail" , "replace" , "append" ] = "fail" ,
937
+ if_exists : Literal ["fail" , "replace" , "append" , "delete_rows" ] = "fail" ,
930
938
prefix : str = "pandas" ,
931
939
index_label = None ,
932
940
schema = None ,
@@ -974,11 +982,13 @@ def create(self) -> None:
974
982
if self .exists ():
975
983
if self .if_exists == "fail" :
976
984
raise ValueError (f"Table '{ self .name } ' already exists." )
977
- if self .if_exists == "replace" :
985
+ elif self .if_exists == "replace" :
978
986
self .pd_sql .drop_table (self .name , self .schema )
979
987
self ._execute_create ()
980
988
elif self .if_exists == "append" :
981
989
pass
990
+ elif self .if_exists == "delete_rows" :
991
+ self .pd_sql .delete_rows (self .name , self .schema )
982
992
else :
983
993
raise ValueError (f"'{ self .if_exists } ' is not valid for if_exists" )
984
994
else :
@@ -997,7 +1007,7 @@ def _execute_insert(self, conn, keys: list[str], data_iter) -> int:
997
1007
Each item contains a list of values to be inserted
998
1008
"""
999
1009
data = [dict (zip (keys , row )) for row in data_iter ]
1000
- result = conn .execute (self .table .insert (), data )
1010
+ result = self . pd_sql .execute (self .table .insert (), data )
1001
1011
return result .rowcount
1002
1012
1003
1013
def _execute_insert_multi (self , conn , keys : list [str ], data_iter ) -> int :
@@ -1014,7 +1024,7 @@ def _execute_insert_multi(self, conn, keys: list[str], data_iter) -> int:
1014
1024
1015
1025
data = [dict (zip (keys , row )) for row in data_iter ]
1016
1026
stmt = insert (self .table ).values (data )
1017
- result = conn .execute (stmt )
1027
+ result = self . pd_sql .execute (stmt )
1018
1028
return result .rowcount
1019
1029
1020
1030
def insert_data (self ) -> tuple [list [str ], list [np .ndarray ]]:
@@ -1480,7 +1490,7 @@ def to_sql(
1480
1490
self ,
1481
1491
frame ,
1482
1492
name : str ,
1483
- if_exists : Literal ["fail" , "replace" , "append" ] = "fail" ,
1493
+ if_exists : Literal ["fail" , "replace" , "append" , "delete_rows" ] = "fail" ,
1484
1494
index : bool = True ,
1485
1495
index_label = None ,
1486
1496
schema = None ,
@@ -1649,7 +1659,7 @@ def run_transaction(self):
1649
1659
else :
1650
1660
yield self .con
1651
1661
1652
- def execute (self , sql : str | Select | TextClause , params = None ):
1662
+ def execute (self , sql : str | Select | TextClause | Delete , params = None ):
1653
1663
"""Simple passthrough to SQLAlchemy connectable"""
1654
1664
from sqlalchemy .exc import SQLAlchemyError
1655
1665
@@ -1874,7 +1884,7 @@ def prep_table(
1874
1884
self ,
1875
1885
frame ,
1876
1886
name : str ,
1877
- if_exists : Literal ["fail" , "replace" , "append" ] = "fail" ,
1887
+ if_exists : Literal ["fail" , "replace" , "append" , "delete_rows" ] = "fail" ,
1878
1888
index : bool | str | list [str ] | None = True ,
1879
1889
index_label = None ,
1880
1890
schema = None ,
@@ -1951,7 +1961,7 @@ def to_sql(
1951
1961
self ,
1952
1962
frame ,
1953
1963
name : str ,
1954
- if_exists : Literal ["fail" , "replace" , "append" ] = "fail" ,
1964
+ if_exists : Literal ["fail" , "replace" , "append" , "delete_rows" ] = "fail" ,
1955
1965
index : bool = True ,
1956
1966
index_label = None ,
1957
1967
schema : str | None = None ,
@@ -1969,10 +1979,11 @@ def to_sql(
1969
1979
frame : DataFrame
1970
1980
name : string
1971
1981
Name of SQL table.
1972
- if_exists : {'fail', 'replace', 'append'}, default 'fail'
1982
+ if_exists : {'fail', 'replace', 'append', 'delete_rows' }, default 'fail'
1973
1983
- fail: If table exists, do nothing.
1974
1984
- replace: If table exists, drop it, recreate it, and insert data.
1975
1985
- append: If table exists, insert data. Create if does not exist.
1986
+ - delete_rows: If a table exists, delete all records and insert data.
1976
1987
index : boolean, default True
1977
1988
Write DataFrame index as a column.
1978
1989
index_label : string or sequence, default None
@@ -2069,6 +2080,16 @@ def drop_table(self, table_name: str, schema: str | None = None) -> None:
2069
2080
self .get_table (table_name , schema ).drop (bind = self .con )
2070
2081
self .meta .clear ()
2071
2082
2083
+ def delete_rows (self , table_name : str , schema : str | None = None ) -> None :
2084
+ schema = schema or self .meta .schema
2085
+ if self .has_table (table_name , schema ):
2086
+ self .meta .reflect (
2087
+ bind = self .con , only = [table_name ], schema = schema , views = True
2088
+ )
2089
+ table = self .get_table (table_name , schema )
2090
+ self .execute (table .delete ())
2091
+ self .meta .clear ()
2092
+
2072
2093
def _create_sql_schema (
2073
2094
self ,
2074
2095
frame : DataFrame ,
@@ -2304,7 +2325,7 @@ def to_sql(
2304
2325
self ,
2305
2326
frame ,
2306
2327
name : str ,
2307
- if_exists : Literal ["fail" , "replace" , "append" ] = "fail" ,
2328
+ if_exists : Literal ["fail" , "replace" , "append" , "delete_rows" ] = "fail" ,
2308
2329
index : bool = True ,
2309
2330
index_label = None ,
2310
2331
schema : str | None = None ,
@@ -2326,6 +2347,7 @@ def to_sql(
2326
2347
- fail: If table exists, do nothing.
2327
2348
- replace: If table exists, drop it, recreate it, and insert data.
2328
2349
- append: If table exists, insert data. Create if does not exist.
2350
+ - delete_rows: If a table exists, delete all records and insert data.
2329
2351
index : boolean, default True
2330
2352
Write DataFrame index as a column.
2331
2353
index_label : string or sequence, default None
@@ -2416,6 +2438,11 @@ def has_table(self, name: str, schema: str | None = None) -> bool:
2416
2438
2417
2439
return False
2418
2440
2441
+ def delete_rows (self , name : str , schema : str | None = None ) -> None :
2442
+ table_name = f"{ schema } .{ name } " if schema else name
2443
+ if self .has_table (name , schema ):
2444
+ self .execute (f"DELETE FROM { table_name } " ).close ()
2445
+
2419
2446
def _create_sql_schema (
2420
2447
self ,
2421
2448
frame : DataFrame ,
@@ -2790,10 +2817,11 @@ def to_sql(
2790
2817
frame: DataFrame
2791
2818
name: string
2792
2819
Name of SQL table.
2793
- if_exists: {'fail', 'replace', 'append'}, default 'fail'
2820
+ if_exists: {'fail', 'replace', 'append', 'delete_rows' }, default 'fail'
2794
2821
fail: If table exists, do nothing.
2795
2822
replace: If table exists, drop it, recreate it, and insert data.
2796
2823
append: If table exists, insert data. Create if it does not exist.
2824
+ delete_rows: If a table exists, delete all records and insert data.
2797
2825
index : bool, default True
2798
2826
Write DataFrame index as a column
2799
2827
index_label : string or sequence, default None
@@ -2869,6 +2897,11 @@ def drop_table(self, name: str, schema: str | None = None) -> None:
2869
2897
drop_sql = f"DROP TABLE { _get_valid_sqlite_name (name )} "
2870
2898
self .execute (drop_sql )
2871
2899
2900
+ def delete_rows (self , name : str , schema : str | None = None ) -> None :
2901
+ delete_sql = f"DELETE FROM { _get_valid_sqlite_name (name )} "
2902
+ if self .has_table (name , schema ):
2903
+ self .execute (delete_sql )
2904
+
2872
2905
def _create_sql_schema (
2873
2906
self ,
2874
2907
frame ,
0 commit comments