Skip to content

Commit eb86524

Browse files
Fix read_sql empty result with chunksize bug GH34411 (#34429)
1 parent 008b10b commit eb86524

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

doc/source/whatsnew/v1.3.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ I/O
281281
- :func:`read_excel` now respects :func:`set_option` (:issue:`34252`)
282282
- Bug in :func:`read_csv` not switching ``true_values`` and ``false_values`` for nullable ``boolean`` dtype (:issue:`34655`)
283283
- Bug in :func:`read_json` when ``orient="split"`` does not maintain numeric string index (:issue:`28556`)
284+
- :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`)
284285

285286
Period
286287
^^^^^^

pandas/io/sql.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,11 +926,17 @@ def _query_iterator(
926926
parse_dates=None,
927927
):
928928
"""Return generator through chunked result set."""
929+
has_read_data = False
929930
while True:
930931
data = result.fetchmany(chunksize)
931932
if not data:
933+
if not has_read_data:
934+
yield DataFrame.from_records(
935+
[], columns=columns, coerce_float=coerce_float
936+
)
932937
break
933938
else:
939+
has_read_data = True
934940
self.frame = DataFrame.from_records(
935941
data, columns=columns, coerce_float=coerce_float
936942
)
@@ -1343,11 +1349,21 @@ def _query_iterator(
13431349
dtype: Optional[DtypeArg] = None,
13441350
):
13451351
"""Return generator through chunked result set"""
1352+
has_read_data = False
13461353
while True:
13471354
data = result.fetchmany(chunksize)
13481355
if not data:
1356+
if not has_read_data:
1357+
yield _wrap_result(
1358+
[],
1359+
columns,
1360+
index_col=index_col,
1361+
coerce_float=coerce_float,
1362+
parse_dates=parse_dates,
1363+
)
13491364
break
13501365
else:
1366+
has_read_data = True
13511367
yield _wrap_result(
13521368
data,
13531369
columns,
@@ -1849,14 +1865,20 @@ def _query_iterator(
18491865
dtype: Optional[DtypeArg] = None,
18501866
):
18511867
"""Return generator through chunked result set"""
1868+
has_read_data = False
18521869
while True:
18531870
data = cursor.fetchmany(chunksize)
18541871
if type(data) == tuple:
18551872
data = list(data)
18561873
if not data:
18571874
cursor.close()
1875+
if not has_read_data:
1876+
yield DataFrame.from_records(
1877+
[], columns=columns, coerce_float=coerce_float
1878+
)
18581879
break
18591880
else:
1881+
has_read_data = True
18601882
yield _wrap_result(
18611883
data,
18621884
columns,

pandas/tests/io/test_sql.py

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

664+
def test_read_sql_with_chunksize_no_result(self):
665+
query = "SELECT * FROM iris_view WHERE SepalLength < 0.0"
666+
with_batch = sql.read_sql_query(query, self.conn, chunksize=5)
667+
without_batch = sql.read_sql_query(query, self.conn)
668+
tm.assert_frame_equal(pd.concat(with_batch), without_batch)
669+
664670
def test_to_sql(self):
665671
sql.to_sql(self.test_frame1, "test_frame1", self.conn)
666672
assert sql.has_table("test_frame1", self.conn)

0 commit comments

Comments
 (0)