Skip to content

Commit bda0257

Browse files
BUG: Fixes GH34411 _query_iterator now returns a list with an empty pd.DataFrame if chunksize is set and the resultset is empty
Added release note
1 parent 361166f commit bda0257

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

doc/source/whatsnew/v1.2.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ I/O
292292
- :meth:`to_csv` passes compression arguments for `'gzip'` always to `gzip.GzipFile` (:issue:`28103`)
293293
- :meth:`to_csv` did not support zip compression for binary file object not having a filename (:issue: `35058`)
294294
- :meth:`to_csv` and :meth:`read_csv` did not honor `compression` and `encoding` for path-like objects that are internally converted to file-like objects (:issue:`35677`, :issue:`26124`, and :issue:`32392`)
295+
- :meth:`read_sql` returned an empty generator if `chunksize` was no-zero and the query returned no results. Now returns a generator with a single empty dataframe (:issue:`34411`)
295296

296297
Plotting
297298
^^^^^^^^

pandas/io/sql.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,11 +834,17 @@ def _query_iterator(
834834
self, result, chunksize, columns, coerce_float=True, parse_dates=None
835835
):
836836
"""Return generator through chunked result set."""
837+
has_read_data = False
837838
while True:
838839
data = result.fetchmany(chunksize)
839840
if not data:
841+
if not has_read_data:
842+
yield DataFrame.from_records(
843+
[], columns=columns, coerce_float=coerce_float
844+
)
840845
break
841846
else:
847+
has_read_data = True
842848
self.frame = DataFrame.from_records(
843849
data, columns=columns, coerce_float=coerce_float
844850
)
@@ -1228,11 +1234,21 @@ def _query_iterator(
12281234
result, chunksize, columns, index_col=None, coerce_float=True, parse_dates=None
12291235
):
12301236
"""Return generator through chunked result set"""
1237+
has_read_data = False
12311238
while True:
12321239
data = result.fetchmany(chunksize)
12331240
if not data:
1241+
if not has_read_data:
1242+
yield _wrap_result(
1243+
[],
1244+
columns,
1245+
index_col=index_col,
1246+
coerce_float=coerce_float,
1247+
parse_dates=parse_dates,
1248+
)
12341249
break
12351250
else:
1251+
has_read_data = True
12361252
yield _wrap_result(
12371253
data,
12381254
columns,
@@ -1698,14 +1714,20 @@ def _query_iterator(
16981714
cursor, chunksize, columns, index_col=None, coerce_float=True, parse_dates=None
16991715
):
17001716
"""Return generator through chunked result set"""
1717+
has_read_data = False
17011718
while True:
17021719
data = cursor.fetchmany(chunksize)
17031720
if type(data) == tuple:
17041721
data = list(data)
17051722
if not data:
17061723
cursor.close()
1724+
if not has_read_data:
1725+
yield DataFrame.from_records(
1726+
[], columns=columns, coerce_float=coerce_float
1727+
)
17071728
break
17081729
else:
1730+
has_read_data = True
17091731
yield _wrap_result(
17101732
data,
17111733
columns,

pandas/tests/io/test_sql.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,12 @@ def test_read_sql_view(self):
612612
iris_frame = sql.read_sql_query("SELECT * FROM iris_view", self.conn)
613613
self._check_iris_loaded_frame(iris_frame)
614614

615+
def test_read_sql_with_chunksize_no_result(self):
616+
query = "SELECT * FROM iris_view WHERE SepalLength < 0.0"
617+
with_batch = sql.read_sql_query(query, self.conn, chunksize=5)
618+
without_batch = sql.read_sql_query(query, self.conn)
619+
tm.assert_frame_equal(pd.concat(with_batch), without_batch)
620+
615621
def test_to_sql(self):
616622
sql.to_sql(self.test_frame1, "test_frame1", self.conn)
617623
assert sql.has_table("test_frame1", self.conn)

0 commit comments

Comments
 (0)