用SQL对 Pandas进行查询,但不返回新的数据框

编程语言 2026-07-10

我正在尝试制作一个小应用程序,可以把CSV和 Parquet文件加载到pandas DataFrame,并让我能够用SQL查询它们并使用matplotlib绘制图表。然而每次查询时,它不会返回一个新的DataFrame。如果我把display_data函数中的if data is none语句删掉,我就会得到如下错误:

AttributeError: 'NoneType' object has no attribute 'columns'

def display_data(dataf):
    if dataf is None:
        return
    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):
    global df
    df2 = sqldf(sql_input)
    display_data(df2)
    return df2


entry_value = tk.Entry(frame_filter, width=20)
entry_value.grid(row=0, column=1, padx=5)
#entry_value.insert(0, "Value")
sql = entry_value.get()

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

解决方案

我没法测试你的代码,但我发现了一些可能导致问题的错误。

你在 command=filter_data(sql) 里有一个常见的错误。它需要的是不带 () 的函数名以及参数 - command=filter_data -,当你点击按钮时,它会使用 () 来执行它。最终你可以使用 lambda 来创建函数名 command=lambda:filter_data(sql),但这似乎没什么用,因为还有另一个错误。

第二个问题:sql = entry_value.get() 只在程序启动时获取数据——在用户把数据输入到 Entry 之前。你必须把 entry_value.get() 直接放在 def filter_data(): 里面,这样每次点击按钮时它都会执行——所以当 Entry 中已经有数据时。

还有第三个问题:分配给 command= 的函数在 mainloop() 的某处被执行,它不知道如何处理返回值 - return df2。如果你以后需要这个DataFrame,就必须把它赋值给全局变量。因此你需要 global df2,或者你得使用现有的 global df 并用 df = ... 来替代 df2 = ...
不过如果你只需要它来运行 display_data(df),那么你就不需要 global


此刻它只在程序启动时执行 filter_data(sql) 一次——并把该函数的返回结果赋值给 command=

result = filter_data(sql)
btn_filter = tk.Button(..., command=result)

我不知道你使用的是什么模块 sqldf,但我找到了这个 sqldf ,它显示的是 sqldf.run(...) 而不是 sql(...)

也许你的 sql(...) 给出了 None,你又有 df2 = None,于是这就产生了 display_data(None),从而导致与 AttributeError: 'NoneType' object has no attribute 'columns 相关的问题。


def filter_data():
    global df

    sql = entry_value.get()  # <-- use directly in function

    df = sqldf(sql)
    display_data(df)

    #return df  # useless 

# --- main ---

entry_value = tk.Entry(frame_filter, width=20)
entry_value.grid(row=0, column=1, padx=5)
# entry_value.insert(0, "Value")

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

与此同时我做了自己的 minimal working code,并测试了模块:sqldfpandasql

看起来 sqldf.run(sql)pandasql.sqldf(sql)sql 是空字符串时会给出 None。而且因为你把 sql = entry_value.get() 放错位置,sql 总是空字符串,这就导致了 df2 = None

模块


用于测试的最小可工作代码:

import tkinter as tk
import pandas as pd
import sqldf
#import pandasql

def filter_sql():
    sql = filter_entry.get()
    if sql:
        # new_df = df.query(sql)  # e.g. `A>13` (built-in function)
        new_df = sqldf.run(sql)  # e.g. `SELECT * FROM df WHERE A>13`
        #new_df = pandasql.sqldf(sql)  # e.g. `SELECT * FROM df WHERE A>13`
    else:
        new_df = df

    output.insert("end", f"Query: {sql}\n")
    output.insert("end", new_df.to_string())
    output.insert("end", "\n---\n")

# --- main ---

df = pd.DataFrame(
    {
        "A": [11, 12, 13, 14, 15],
        "B": [21, 22, 23, 24, 25],
        "C": [31, 32, 33, 34, 35],
        "D": [41, 42, 43, 44, 45],
    }
)

root = tk.Tk()

filter_entry = tk.Entry(root)
filter_entry.pack()

button = tk.Button(root, text="Filter", command=filter_sql)
button.pack()

output = tk.Text()
output.pack()

root.mainloop()

在此输入图片描述

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章