Skip to content

Commit c2b8c45

Browse files
Merge pull request #6709 from gpoulin2/master
BUG: Allow mapping as parameters for SQL DBAPI2
2 parents 2ada054 + 4cf59fe commit c2b8c45

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

pandas/io/sql.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ def _convert_params(sql, params):
3131
"""convert sql and params args to DBAPI2.0 compliant format"""
3232
args = [sql]
3333
if params is not None:
34-
args += list(params)
34+
if hasattr(params, 'keys'): # test if params is a mapping
35+
args += [params]
36+
else:
37+
args += [list(params)]
3538
return args
3639

3740

@@ -200,7 +203,7 @@ def read_sql(sql, con, index_col=None, flavor='sqlite', coerce_float=True,
200203
Attempt to convert values to non-string, non-numeric objects (like
201204
decimal.Decimal) to floating point, useful for SQL result sets
202205
cur : depreciated, cursor is obtained from connection
203-
params : list or tuple, optional
206+
params : list, tuple or dict, optional
204207
List of parameters to pass to execute method.
205208
parse_dates : list or dict
206209
- List of column names to parse as dates

pandas/io/tests/test_sql.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@
9595
INSERT INTO types_test_data
9696
VALUES(%s, %s, %s, %s, %s, %s, %s, %s)
9797
"""
98+
},
99+
'read_parameters': {
100+
'sqlite': "SELECT * FROM iris WHERE Name=? AND SepalLength=?",
101+
'mysql': 'SELECT * FROM iris WHERE `Name`="%s" AND `SepalLength`=%s',
102+
'postgresql': 'SELECT * FROM iris WHERE "Name"=%s AND "SepalLength"=%s'
103+
},
104+
'read_named_parameters': {
105+
'sqlite': """
106+
SELECT * FROM iris WHERE Name=:name AND SepalLength=:length
107+
""",
108+
'mysql': """
109+
SELECT * FROM iris WHERE
110+
`Name`="%(name)s" AND `SepalLength`=%(length)s
111+
""",
112+
'postgresql': """
113+
SELECT * FROM iris WHERE
114+
"Name"=%(name)s AND "SepalLength"=%(length)s
115+
"""
98116
}
99117
}
100118

@@ -168,6 +186,18 @@ def _read_sql_iris(self):
168186
iris_frame = self.pandasSQL.read_sql("SELECT * FROM iris")
169187
self._check_iris_loaded_frame(iris_frame)
170188

189+
def _read_sql_iris_parameter(self):
190+
query = SQL_STRINGS['read_parameters'][self.flavor]
191+
params = ['Iris-setosa', 5.1]
192+
iris_frame = self.pandasSQL.read_sql(query, params=params)
193+
self._check_iris_loaded_frame(iris_frame)
194+
195+
def _read_sql_iris_named_parameter(self):
196+
query = SQL_STRINGS['read_named_parameters'][self.flavor]
197+
params = {'name': 'Iris-setosa', 'length': 5.1}
198+
iris_frame = self.pandasSQL.read_sql(query, params=params)
199+
self._check_iris_loaded_frame(iris_frame)
200+
171201
def _to_sql(self):
172202
self.drop_table('test_frame1')
173203

@@ -491,6 +521,12 @@ class _TestSQLAlchemy(PandasSQLTest):
491521
def test_read_sql(self):
492522
self._read_sql_iris()
493523

524+
def test_read_sql_parameter(self):
525+
self._read_sql_iris_parameter()
526+
527+
def test_read_sql_named_parameter(self):
528+
self._read_sql_iris_named_parameter()
529+
494530
def test_to_sql(self):
495531
self._to_sql()
496532

@@ -703,6 +739,12 @@ def test_invalid_flavor(self):
703739
def test_read_sql(self):
704740
self._read_sql_iris()
705741

742+
def test_read_sql_parameter(self):
743+
self._read_sql_iris_parameter()
744+
745+
def test_read_sql_named_parameter(self):
746+
self._read_sql_iris_named_parameter()
747+
706748
def test_to_sql(self):
707749
self._to_sql()
708750

0 commit comments

Comments
 (0)