0

0

使用Python和SQLite实现多表关联查询:动态获取球队表现与对手球员信息

心靈之曲

心靈之曲

发布时间:2025-12-07 15:51:06

|

142人浏览过

|

来源于php中文网

原创

使用python和sqlite实现多表关联查询:动态获取球队表现与对手球员信息

本文详细阐述如何利用Python和SQLite数据库,根据用户输入的球队名称,从两个关联表(球队表现数据和球员深度名单)中高效地查询并组合数据。核心在于通过自定义行工厂增强数据可读性,并根据一支球队的表现记录,动态匹配另一支指定球队中相同位置的球员,最终生成一份整合了球队表现与对手球员信息的报告。

引言

在数据分析和应用开发中,我们常遇到需要从多个关联表中提取信息,并根据用户动态输入进行复杂条件筛选的场景。本教程将以一个NBA数据分析为例,展示如何使用Python的sqlite3模块,结合SQL查询,实现从两个不同的数据表中(一个存储球队表现数据,另一个存储球员名单)根据用户指定的两支球队,获取一支球队的详细表现,并关联查询另一支球队中对应位置的球员信息。

数据库结构概览

我们假设有两个SQLite数据库表:Cheatsheet 和 Teamdepth。

  1. Cheatsheet 表:存储球队的各项表现数据。

    立即学习Python免费学习笔记(深入)”;

    • Teamname (TEXT): 球队名称,可能包含缩写。
    • threeRPA (TEXT): 表现类型(例如:Points, Rebounds)。
    • Value (REAL): 表现数值。
    • Pos (TEXT): 球员位置(例如:Center (C), Power Forward (PF))。
  2. Teamdepth 表:存储球队的球员名单及其位置。

    • Teamname (TEXT): 球队名称。
    • Player (TEXT): 球员姓名。
    • Pos (TEXT): 球员位置。
    • Con (TEXT): 其他信息(此处不使用)。

为了方便演示,我们首先创建这些表并插入示例数据:

-- 创建 Cheatsheet 表
CREATE TABLE IF NOT EXISTS Cheatsheet (
    Teamname TEXT,
    threeRPA TEXT,
    Value REAL,
    Pos TEXT
);

-- 插入 Cheatsheet 示例数据
INSERT INTO Cheatsheet (Teamname, threeRPA, Value, Pos) VALUES
('Washington Wizards (WAS)', 'Points', 27.9, 'Center (C)'),
('San Antonio Spurs (SA)', 'Points', 25.4, 'Center (C)'),
('Charlotte Hornets (CHA)', 'Points', 25.3, 'Center (C)'),
('Philadelphia 76ers (PHI)', 'Points', 24.1, 'Center (C)'),
('Detroit Pistons (DET)', 'Points', 23.8, 'Center (C)'),
('Chicago Bulls (CHI)', 'Points', 23.4, 'Center (C)'),
('Dallas Mavericks (DAL)', 'Points', 23.4, 'Center (C)'),
('Washington Wizards (WAS)', 'Rebounds', 18.0, 'Center (C)'),
('Chicago Bulls (CHI)', 'Rebounds', 12.0, 'Power Forward (PF)'),
('Portland Trail Blazers (POR)', 'Rebounds', 11.4, 'Power Forward (PF)'),
('Oklahoma City Thunder (OKC)', 'Rebounds', 11.3, 'Power Forward (PF)'),
('Washington Wizards (WAS)', 'Rebounds', 11.3, 'Power Forward (PF)'),
('Atlanta Hawks (ATL)', 'Rebounds', 11.0, 'Power Forward (PF)'),
('Denver Nuggets (DEN)', 'Rebounds', 10.8, 'Power Forward (PF)'),
('Charlotte Hornets (CHA)', 'Rebounds', 10.8, 'Power Forward (PF)');

-- 创建 Teamdepth 表
CREATE TABLE IF NOT EXISTS Teamdepth (
    Teamname TEXT,
    Player TEXT,
    Pos TEXT,
    Con TEXT
);

-- 插入 Teamdepth 示例数据
INSERT INTO Teamdepth (Teamname, Player, Pos, Con) VALUES
('Atlanta Hawks (ATL)', 'Trae Young', 'Point Guard (PG)', ''),
('Atlanta Hawks (ATL)', 'Dejounte Murray', 'Shooting Guard (SG)', ''),
('Atlanta Hawks (ATL)', 'Saddiq Bey', 'Small Forward (SF)', ''),
('Atlanta Hawks (ATL)', 'Jalen Johnson', 'Power Forward (PF)', ''),
('Atlanta Hawks (ATL)', 'Clint Capela', 'Center (C)', ''),
('Denver Nuggets (DEN)', 'Jamal Murray', 'Point Guard (PG)', ''),
('Dallas Mavericks (DAL)', 'Derrick Jones', 'Power Forward (PF)', ''),
('Denver Nuggets (DEN)', 'Nikola Jokic', 'Center (C)', ''),
('Atlanta Hawks (ATL)', 'Onyeka Okongwu', 'Center (C)', ''),
('Washington Wizards (WAS)', 'Kyle Kuzma', 'Power Forward (PF)', '');

核心逻辑与实现

我们的目标是:

闪念贝壳
闪念贝壳

闪念贝壳是一款AI 驱动的智能语音笔记,随时随地用语音记录你的每一个想法。

下载
  1. 用户输入两支球队的名称(可以是全名或缩写)。
  2. 对于第一支球队的每条表现记录(例如,华盛顿奇才队中锋位置的得分),找到第二支球队中所有担任相同位置的球员。
  3. 反之亦然,对于第二支球队的每条表现记录,找到第一支球队中所有担任相同位置的球员。
  4. 将这些信息整合输出。

为了提高代码的可读性和可维护性,我们将采用collections.namedtuple来定义数据结构,并利用sqlite3的row_factory功能将查询结果自动映射到这些具名元组。

1. 定义数据结构

使用namedtuple为Cheatsheet、Teamdepth以及最终输出结果定义清晰的数据模型。

import collections
import sqlite3

# 定义具名元组,对应数据库表结构和最终输出结构
Cheatsheet = collections.namedtuple("Cheatsheet", "teamname,threerpa,value,pos")
Teamdepth = collections.namedtuple("Teamdepth", "teamname,player,pos")
Output = collections.namedtuple("Output", "teamname,threerpa,value,pos,players")

2. 自定义行工厂 custom_row_factory

sqlite3默认返回的查询结果是元组。通过自定义row_factory,我们可以让cursor返回具名元组,从而可以通过属性名而不是索引来访问数据,极大地提升代码可读性

def custom_row_factory(cursor: sqlite3.Cursor, row: tuple):
    """
    自定义行工厂,根据查询的字段名返回对应的具名元组。
    """
    field_names = tuple(x[0] for x in cursor.description)

    if field_names == Cheatsheet._fields:
        return Cheatsheet(*row)
    elif field_names == Teamdepth._fields:
        return Teamdepth(*row)
    elif len(row) == 1: # 针对单列查询(如获取球员列表)
        return row[0]
    return row

3. 查询函数 show_team

这个函数负责查询指定球队的表现数据,并根据其位置信息,从对手球队中查找对应的球员。

def show_team(conn: sqlite3.Connection, this_team_abbr: str, opposition_team_abbr: str):
    """
    查询指定球队的表现数据,并关联查询对手球队中相同位置的球员。

    Args:
        conn: SQLite数据库连接对象。
        this_team_abbr: 当前查询球队的缩写(如 'WAS')。
        opposition_team_abbr: 对手球队的缩写(如 'ATL')。

    Returns:
        一个包含 Output 具名元组的列表。
    """
    # 查询当前球队的 Cheatsheet 数据
    # 使用 LIKE '%{team_abbr}%' 来匹配包含缩写或完整名称的球队
    cheat_data = conn.execute(
        "SELECT Teamname, threeRPA, Value, Pos FROM Cheatsheet WHERE teamname LIKE ?",
        (f"%{this_team_abbr}%",),
    )

    rows = []
    for row in cheat_data:
        # 对于每条表现记录,查询对手球队中相同位置的球员
        players_cursor = conn.execute(
            "SELECT Player FROM Teamdepth WHERE teamname LIKE ? AND Pos = ?",
            (f"%{opposition_team_abbr}%", row.pos),
        )
        players = players_cursor.fetchall() # fetchall() 返回的是一个列表的列表,需要处理

        # 将球员姓名用逗号连接起来
        player_names = ",".join(players) if players else "N/A"

        # 构建 Output 具名元组并添加到结果列表
        rows.append(Output(row.teamname, row.threerpa, row.value, row.pos, player_names))

    return rows

4. 主执行函数 main

main函数将连接数据库,设置行工厂,获取用户输入,并调用show_team函数来处理两支球队的数据。

def main():
    """程序入口点"""
    # 连接到数据库,使用 with 语句确保连接正确关闭
    with sqlite3.connect("NBA.db") as conn:
        # 设置自定义行工厂
        conn.row_factory = custom_row_factory
        cursor = conn.cursor()

        # 确保表存在并包含数据,仅在第一次运行时需要
        # 为了教程的完整性,这里再次执行创建和插入数据的SQL
        # 实际应用中,这些操作通常在数据库初始化脚本中完成
        cursor.executescript("""
            CREATE TABLE IF NOT EXISTS Cheatsheet (Teamname TEXT, threeRPA TEXT, Value REAL, Pos TEXT);
            CREATE TABLE IF NOT EXISTS Teamdepth (Teamname TEXT, Player TEXT, Pos TEXT, Con TEXT);

            INSERT OR IGNORE INTO Cheatsheet (Teamname, threeRPA, Value, Pos) VALUES
            ('Washington Wizards (WAS)', 'Points', 27.9, 'Center (C)'),
            ('San Antonio Spurs (SA)', 'Points', 25.4, 'Center (C)'),
            ('Charlotte Hornets (CHA)', 'Points', 25.3, 'Center (C)'),
            ('Philadelphia 76ers (PHI)', 'Points', 24.1, 'Center (C)'),
            ('Detroit Pistons (DET)', 'Points', 23.8, 'Center (C)'),
            ('Chicago Bulls (CHI)', 'Points', 23.4, 'Center (C)'),
            ('Dallas Mavericks (DAL)', 'Points', 23.4, 'Center (C)'),
            ('Washington Wizards (WAS)', 'Rebounds', 18.0, 'Center (C)'),
            ('Chicago Bulls (CHI)', 'Rebounds', 12.0, 'Power Forward (PF)'),
            ('Portland Trail Blazers (POR)', 'Rebounds', 11.4, 'Power Forward (PF)'),
            ('Oklahoma City Thunder (OKC)', 'Rebounds', 11.3, 'Power Forward (PF)'),
            ('Washington Wizards (WAS)', 'Rebounds', 11.3, 'Power Forward (PF)'),
            ('Atlanta Hawks (ATL)', 'Rebounds', 11.0, 'Power Forward (PF)'),
            ('Denver Nuggets (DEN)', 'Rebounds', 10.8, 'Power Forward (PF)'),
            ('Charlotte Hornets (CHA)', 'Rebounds', 10.8, 'Power Forward (PF)');

            INSERT OR IGNORE INTO Teamdepth (Teamname, Player, Pos, Con) VALUES
            ('Atlanta Hawks (ATL)', 'Trae Young', 'Point Guard (PG)', ''),
            ('Atlanta Hawks (ATL)', 'Dejounte Murray', 'Shooting Guard (SG)', ''),
            ('Atlanta Hawks (ATL)', 'Saddiq Bey', 'Small Forward (SF)', ''),
            ('Atlanta Hawks (ATL)', 'Jalen Johnson', 'Power Forward (PF)', ''),
            ('Atlanta Hawks (ATL)', 'Clint Capela', 'Center (C)', ''),
            ('Denver Nuggets (DEN)', 'Jamal Murray', 'Point Guard (PG)', ''),
            ('Dallas Mavericks (DAL)', 'Derrick Jones', 'Power Forward (PF)', ''),
            ('Denver Nuggets (DEN)', 'Nikola Jokic', 'Center (C)', ''),
            ('Atlanta Hawks (ATL)', 'Onyeka Okongwu', 'Center (C)', ''),
            ('Washington Wizards (WAS)', 'Kyle Kuzma', 'Power Forward (PF)', '');
        """)
        conn.commit() # 提交更改

        # 获取用户输入
        team1_input = input("请输入第一支球队的缩写(例如 WAS):").strip().upper()
        team2_input = input("请输入第二支球队的缩写(例如 ATL):").strip().upper()

        # 定义输出格式
        fmt = "%-30s %-10s %6.1f %-20s %s"
        print(fmt % ("Teamname", "Stat", "Value", "Position", "Opponent Players"))
        print("-" * 90)

        # 显示第一支球队对阵第二支球队的数据
        print(f"\n--- {team1_input} 的表现 vs. {team2_input} 的球员 ---")
        for row in show_team(conn, team1_input, team2_input):
            print(fmt % row)

        # 显示第二支球队对阵第一支球队的数据
        print(f"\n--- {team2_input} 的表现 vs. {team1_input} 的球员 ---")
        for row in show_team(conn, team2_input, team1_input):
            print(fmt % row)

if __name__ == "__main__":
    main()

运行与输出示例

当您运行上述Python代码时,程序会提示您输入两支球队的缩写。 假设输入 WAS 和 ATL:

请输入第一支球队的缩写(例如 WAS):WAS
请输入第二支球队的缩写(例如 ATL):ATL
Teamname                       Stat       Value Position             Opponent Players
------------------------------------------------------------------------------------------

--- WAS 的表现 vs. ATL 的球员 ---
Washington Wizards (WAS)       Points       27.9 Center (C)           Clint Capela,Onyeka Okongwu
Washington Wizards (WAS)       Rebounds     18.0 Center (C)           Clint Capela,Onyeka Okongwu
Washington Wizards (WAS)       Rebounds     11.3 Power Forward (PF)   Jalen Johnson

--- ATL 的表现 vs. WAS 的球员 ---
Atlanta Hawks (ATL)            Rebounds     11.0 Power Forward (PF)   Kyle Kuzma

注意事项与总结

  1. 团队名称匹配:在SQL查询中使用了 LIKE '%{team_abbr}%',这允许用户输入球队缩写(如WAS)就能匹配到完整的球队名称(如Washington Wizards (WAS))。这增加了用户输入的灵活性。
  2. namedtuple 的优势:通过collections.namedtuple和custom_row_factory,我们使得从数据库获取的数据可以直接通过有意义的属性名(如row.teamname, row.pos)访问,而不是通过索引(如row[0], row[3]),极大地提高了代码的可读性和可维护性。
  3. 循环查询的效率:本方案采用循环(先查询表现数据,再对每条表现记录查询对手球员)而非复杂的SQL JOIN。对于数据量不是特别巨大的情况,这种方式清晰易懂且性能可接受。如果数据量非常庞大,可能需要考虑更复杂的SQL JOIN语句来优化查询效率,但会牺牲部分代码可读性。
  4. 错误处理:示例代码中对于没有找到对应球员的情况,简单地输出"N/A"。在实际应用中,可以根据需求增加更详细的错误处理或用户反馈机制。
  5. 数据库初始化:为了使教程完整可复现,main函数中包含了创建表和插入数据的SQL。在实际项目中,这些通常是独立的数据库初始化脚本,而非每次运行Python程序时都执行。INSERT OR IGNORE语句确保数据不会重复插入。

通过本教程,您应该掌握了如何使用Python的sqlite3模块,结合自定义行工厂和SQL查询,灵活地从多个关联表中提取和整合数据,以满足复杂的业务需求,特别是涉及到用户动态输入和多条件匹配的场景。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

1135

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

340

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

381

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2194

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

380

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

1703

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

586

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

440

2024.04.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号