动态 Python SQL 语句,其列名称来自数据库的值

问题描述 投票:0回答:1

我有一张包含姓名、年份和分数/计数的表格:

 ("Andi", 2020, 40),
 ("Andi", 2021, 60),
 ("Andi", 2022, 55),
 ("Andi", 2023, 55),
 ("Alex", 2020, 14),
 ("Alex", 2021, 1),
 ("Alex", 2022, 13),
 ("Alex", 2023, 13),
 ...

我尝试使用 writefile() 等将其压缩到 Excel 文件中。 它应该看起来像这样

姓名 2020 2021 2022 2023 总计
安迪 40 60 55 55 210
亚历克斯 14 1 13 13 41

ofc 明年他们将添加新记录: (“安迪”,2024,49),(“亚历克斯”,2024,10),... 因此,当我明年再次重新创建 Excel 文件时,sqlstament 也应该添加。 我发现了这个: 如何在SQL表中以条件选择列值作为列名 这是硬编码的,可以按照我想要的方式工作,但我不想每年都改变它。 我的数据库也是从 2016 年开始的,所以这将是一个很长的声明。 我尝试为 select、from、on 制作 for 循环,但我认为可能有更简单的方法?

我有什么想法可以实现这一目标吗? 谢谢你

python sql sqlite
1个回答
2
投票

您可以使用如下所示的 SQL 查询将列名称旋转为年份。

SELECT name, 
MAX(CASE WHEN year = 2020 THEN score END) AS '2020', 
MAX(CASE WHEN year = 2021 THEN score END) AS '2021',
 MAX(CASE WHEN year = 2022 THEN score END) AS '2022',
 MAX(CASE WHEN year = 2023 THEN score END) AS '2023',
 MAX(CASE WHEN year = 2024 THEN score END) AS '2024', 
 COALESCE(MAX(CASE WHEN year = 2020 THEN score END), 0)+COALESCE(MAX(CASE WHEN year = 2021 THEN score END), 0)+COALESCE(MAX(CASE WHEN year = 2022 THEN score END), 0)+COALESCE(MAX(CASE WHEN year = 2023 THEN score END), 0)+COALESCE(MAX(CASE WHEN year = 2024 THEN score END), 0) AS total
 FROM scores
 GROUP BY name
 ORDER BY name;

这可以在添加新的年份时动态生成。

# Get all the years
cursor.execute("SELECT DISTINCT year FROM scores ORDER BY year")
years = cursor.fetchall()

# Generate the pivot columns as years
columns = []
for year in years:
    columns.append(f"MAX(CASE WHEN year = {year[0]} THEN score END) AS '{year[0]}'")

columns_str = ", ".join(columns)



sql = f"""
SELECT name, {columns_str}, 
       {"+".join([f"COALESCE(MAX(CASE WHEN year = {year[0]} THEN score END), 0)" for year in years])} AS total
FROM scores
GROUP BY name
ORDER BY name;
"""


cursor.execute(sql)
result = cursor.fetchall()

df = pd.DataFrame.from_records(result, columns=['name'] + [str(year[0]) for year in years] + ['total'])
print(df)

输出

   name  2020  2021  2022  2023  2024  total
0  Alex    14     1    13    13    10     51
1  Andi    40    60    55    55    49    259
© www.soinside.com 2019 - 2024. All rights reserved.