PAYATHON 2026

使用 SQL 查询 pandas 时为何没有返回新的 DataFrame?

数据小许

代码中有两处可以直接确认:command=filter_data(sql) 在创建按钮时就执行了查询,输入框的值也在创建后立即被读取。应将函数作为回调交给按钮,并在点击时读取 SQL。

AttributeError: 'NoneType' object has no attribute 'columns' 说明传给 display_data() 的对象是 None。题目没有提供 sqldf() 的导入方式和实际执行的 SQL,因此仅凭这段代码无法确定它为什么返回 None。

为什么查询没有按预期执行?

这行代码在创建按钮时就调用了函数:

btn_filter = tk.Button(frame_filter, text="Filter", command=filter_data(sql))

Python 会先执行 filter_data(sql),再把返回值传给 command,没有为按钮注册预期的查询回调。

此外,输入框刚创建时就读取了它的值:

sql = entry_value.get()

所示代码没有设置初始内容,所以此时读到的是空字符串。之后用户在输入框中输入 SQL,变量 sql 也不会随之更新。

可以先将按钮改成:

btn_filter = tk.Button(
    frame_filter,
    text="Filter",
    command=lambda: filter_data(entry_value.get())
)

这样,点击按钮时才会读取输入并调用查询函数。

如何显示查询返回的 DataFrame?

下面是完整的相关代码。示例假设 sqldf 来自 pandasql,CSV 或 parquet 文件已加载到 df,并且 tree、frame_filter 已经创建。如果使用其他同名函数,需要按其接口调整查询调用。

import tkinter as tk
from tkinter import messagebox
from pandasql import sqldf


def display_data(dataf):
    tree.delete(*tree.get_children())
    tree["columns"] = list(dataf.columns)
    tree["show"] = "headings"

    for col in dataf.columns:
        tree.heading(col, text=col)
        tree.column(col, width=150)

    for _, row in dataf.iterrows():
        tree.insert("", "end", values=list(row))


def filter_data():
    sql_input = entry_value.get().strip()
    if not sql_input:
        messagebox.showwarning("提示", "请先输入 SQL 查询。")
        return

    try:
        result = sqldf(sql_input, {"df": df})
        if result is None:
            raise ValueError("sqldf 返回了 None,请检查 SQL 和函数来源。")
        display_data(result)
    except Exception as exc:
        messagebox.showerror("查询失败", str(exc))
        return

    return result


entry_value = tk.Entry(frame_filter, width=40)
entry_value.grid(row=0, column=1, padx=5)
entry_value.insert(0, "SELECT * FROM df LIMIT 10;")

btn_filter = tk.Button(
    frame_filter,
    text="Filter",
    command=filter_data
)
btn_filter.grid(row=0, column=2, padx=5)

两处设置需要注意:

  • command=filter_data 传入函数本身,不加调用括号。点击按钮时,函数才会读取输入框。
  • sqldf(sql_input, {"df": df}) 显式提供查询环境,让 SQL 中的表名 df 对应已经加载的 DataFrame。

例如,输入下面的查询可以尝试读取前 10 行:

SELECT * FROM df LIMIT 10;

如果仍然得到 None,应该检查什么?

先确认 sqldf 的实际来源和传入的 SQL。可以在查询前后临时加入:

print("SQL:", repr(sql_input))
result = sqldf(sql_input, {"df": df})
print("Result type:", type(result))

repr(sql_input) 可以帮助发现空字符串或只有空白字符的输入。还要确认查询使用了环境中提供的表名,且用于获取数据的语句是预期的 SELECT 查询。

原来的 if dataf is None: return 只会跳过显示,无法解释查询为什么没有结果。排查时应保留明确的错误提示。正常返回的 DataFrame 即使没有匹配行,也仍有 columns 属性;“结果没有行”和“结果是 None”需要分别处理。

Tkinter 按钮不会自动使用回调的返回值。return result 可供直接调用函数时使用,界面更新仍由 display_data(result) 完成。如果后续绘图需要查询结果,应另行保存。示例保留了原始 df,没有用查询结果覆盖它。

问题中粘贴的代码缺少函数体和循环体的缩进;实际 Python 文件需要像修正示例一样正确缩进。

备注:内容仅供参考。