一文学会一点python数据分析-小白原地进阶(mysql 安装 - mysql - python 数据分析 - 学习阶段梳理)

文章目录

    • [📦 mysql - 安装包下载(目的是:动手实操)](#📦 mysql - 安装包下载(目的是:动手实操))
    • [📦 学习阶段一:win11 下 数据库安装(win系统通用 - 目的是可以给其他人 安装数据库 - 有机会装一下)](#📦 学习阶段一:win11 下 数据库安装(win系统通用 - 目的是可以给其他人 安装数据库 - 有机会装一下))
    • [📦 学习阶段二:打开 mysql 命令行客户端(目的是熟悉 常用sql命令)](#📦 学习阶段二:打开 mysql 命令行客户端(目的是熟悉 常用sql命令))
    • [📦 学习阶段三:使用 Navicat 进行数据库管理访问(目的是:通过图形界面 快速操作数据库、你可以认为它是数据库的图形化操作系统【管理工具】)](#📦 学习阶段三:使用 Navicat 进行数据库管理访问(目的是:通过图形界面 快速操作数据库、你可以认为它是数据库的图形化操作系统【管理工具】))
        • 建立数据库连接
        • [数据库 表管理(替代 命令窗口)](#数据库 表管理(替代 命令窗口))
        • [创建 zx_book 数据库和3个表](#创建 zx_book 数据库和3个表)
    • [📦 学习阶段四:pycharm(编辑器) 写 python 程序 (基于conda环境、数据库增删改查) (目的是:基于python学会一点数据报表、数据分析)](#📦 学习阶段四:pycharm(编辑器) 写 python 程序 (基于conda环境、数据库增删改查) (目的是:基于python学会一点数据报表、数据分析))
      • [📦 项目结构(请创建以下文件)](#📦 项目结构(请创建以下文件))
      • [1️⃣ `requirements.txt`(依赖包)](#1️⃣ requirements.txt(依赖包))
      • [2️⃣ `config.py`(数据库配置)](#2️⃣ config.py(数据库配置))
      • [3️⃣ `generate_mock_data.py`(生成2025年全年模拟数据)](#3️⃣ generate_mock_data.py(生成2025年全年模拟数据))
      • [4️⃣ `queries.py`(所有数据查询逻辑)](#4️⃣ queries.py(所有数据查询逻辑))
      • [5️⃣ `app.py`(Flask 主程序)](#5️⃣ app.py(Flask 主程序))
      • [6️⃣ `templates/index.html`(前端页面)](#6️⃣ templates/index.html(前端页面))
      • [▶️ 使用步骤(小白友好)](#▶️ 使用步骤(小白友好))
    • [📦 学习阶段五:各种丰富的多表联合 - 增删改查](#📦 学习阶段五:各种丰富的多表联合 - 增删改查)
    • [❤️ 一起学习用 AI 创造可能](#❤️ 一起学习用 AI 创造可能)

📦 mysql - 安装包下载(目的是:动手实操)

📦 学习阶段一:win11 下 数据库安装(win系统通用 - 目的是可以给其他人 安装数据库 - 有机会装一下)

  • 最小单元安装 - 只安装 Server 端即可

剩下的基本 一路默认就好了








📦 学习阶段二:打开 mysql 命令行客户端(目的是熟悉 常用sql命令)

  • mysql 命令行客户端 是数据库本身提供的命令行交互工具(类似于 win系统的 cmd 命令窗口、Linux 的 shell 交互窗口)


创建数据库、查询数据库

bash 复制代码
mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| school             |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> CREATE DATABASE mydatabase
    ->   CHARACTER SET utf8mb4
    ->   COLLATE utf8mb4_general_ci;
Query OK, 1 row affected (0.00 sec)

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydatabase         |
| mysql              |
| performance_schema |
| school             |
| sys                |
+--------------------+
6 rows in set (0.00 sec)

mysql> use mydatabase;
Database changed
mysql> SELECT * FROM person;
+----------------+------+----+
| name           | age  | id |
+----------------+------+----+
| Yokoyama Ayato |  315 |  1 |
| Paul Taylor    |  940 |  2 |
| Yip Kwok Kuen  |  871 |  3 |
| Luo Yunxi      |  845 |  4 |
| Edith Perry    |  382 |  5 |
| Carl Owens     |  155 |  6 |
| Duan Yuning    |  963 |  7 |
| Yu Jialun      |  931 |  8 |
| 11             |   21 | 10 |
+----------------+------+----+
9 rows in set (0.00 sec)
建立数据库连接
数据库 表管理(替代 命令窗口)
创建 zx_book 数据库和3个表
  • 借助 Navicat 的命令列界面即可执行 sql 命令

📦 学习阶段四:pycharm(编辑器) 写 python 程序 (基于conda环境、数据库增删改查) (目的是:基于python学会一点数据报表、数据分析)

这里呢,直接去用某个大模型产品、提出你的需求,告诉他 我的数据库用户信息即可

  • 示例要求如下
bash 复制代码
我在做数据分析运营,请帮我设计一套完整的 python数据分析 前后端程序;以中信书店为目标场景,我希望在前端网页建立书本销量、用户 等周期性数据看板;首先请你写一个脚本帮我模拟一个年度的每天用户数据、销量数据;写入到我的数据库中;其次请你丰富前端的数据看板,我觉得应该有一些基础的数据条件查询;增加"区域销售热力图"(需用户地址字段)
添加"复购率"、"客单价"指标
支持时间范围筛选(前端传参 → 后端动态查询)

我的数据库是mysql;数据库连接信息为:

db = mysql.connector.connect(
    host="localhost",
    user="root",
    password="123456",
    database="zx_book"
)

通过 某大模型 (通以千问)的返回生成如下

没问题!作为小白程序员,你只需要按步骤操作即可。下面我为你打包一个 完整可运行的项目,包含:

  • ✅ 模拟数据生成脚本
  • ✅ Flask 后端(带时间筛选、复购率、客单价、省份销量)
  • ✅ 前端看板(含日期选择器 + 6个图表 + KPI卡片)
  • ✅ 所有依赖和说明

📦 项目结构(请创建以下文件)

bash 复制代码
zx_book_dashboard/
├── config.py
├── generate_mock_data.py
├── queries.py
├── app.py
├── requirements.txt
└── templates/
    └── index.html

1️⃣ requirements.txt(依赖包)

txt 复制代码
flask
mysql-connector-python
pandas

安装命令:pip install -r requirements.txt


2️⃣ config.py(数据库配置)

python 复制代码
# config.py
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': '123456',
    'database': 'zx_book'
}

3️⃣ generate_mock_data.py(生成2025年全年模拟数据)

python 复制代码
# generate_mock_data.py
import mysql.connector
import random
from datetime import datetime, timedelta
from config import DB_CONFIG

CITY_PROVINCE = {
    '北京': '北京市', '上海': '上海市', '广州': '广东省', '深圳': '广东省',
    '杭州': '浙江省', '成都': '四川省', '武汉': '湖北省', '西安': '陕西省',
    '南京': '江苏省', '天津': '天津市', '重庆': '重庆市', '苏州': '江苏省',
    '郑州': '河南省', '长沙': '湖南省', '青岛': '山东省', '大连': '辽宁省'
}

BOOK_TITLES = [
    '认知觉醒', '原则', '人类简史', '三体', '活着', '穷查理宝典',
    'Python数据分析', '时间简史', '小王子', '围城', '百年孤独', '追风筝的人'
]

BOOK_CATEGORIES = ['文学', '社科', '经管', '科技', '生活', '少儿', '艺术', '历史']

def create_tables(conn):
    cursor = conn.cursor()
    cursor.execute("DROP TABLE IF EXISTS orders, users, books")
    
    cursor.execute("""
        CREATE TABLE books (
            book_id INT PRIMARY KEY AUTO_INCREMENT,
            title VARCHAR(100),
            category VARCHAR(50),
            price DECIMAL(10,2)
        )
    """)
    
    cursor.execute("""
        CREATE TABLE users (
            user_id INT PRIMARY KEY AUTO_INCREMENT,
            username VARCHAR(50),
            reg_date DATE,
            city VARCHAR(50),
            province VARCHAR(50)
        )
    """)
    
    cursor.execute("""
        CREATE TABLE orders (
            order_id INT PRIMARY KEY AUTO_INCREMENT,
            user_id INT,
            book_id INT,
            order_date DATETIME,
            quantity INT,
            total_price DECIMAL(10,2),
            FOREIGN KEY (user_id) REFERENCES users(user_id),
            FOREIGN KEY (book_id) REFERENCES books(book_id)
        )
    """)
    conn.commit()

def insert_mock_data():
    conn = mysql.connector.connect(**DB_CONFIG)
    create_tables(conn)
    cursor = conn.cursor()

    # 插入书籍
    books = []
    for i, title in enumerate(BOOK_TITLES):
        cat = random.choice(BOOK_CATEGORIES)
        price = round(random.uniform(25, 89), 2)
        books.append((i+1, title, cat, price))
    cursor.executemany("INSERT INTO books (book_id, title, category, price) VALUES (%s, %s, %s, %s)", books)

    # 插入用户
    users = []
    user_id = 1
    start_date = datetime(2025, 1, 1)
    end_date = datetime(2025, 12, 31)
    current = start_date
    while current <= end_date:
        daily_new = random.randint(10, 30)
        for _ in range(daily_new):
            city = random.choice(list(CITY_PROVINCE.keys()))
            province = CITY_PROVINCE[city]
            users.append((user_id, f"user_{user_id}", current.date(), city, province))
            user_id += 1
        current += timedelta(days=1)
    cursor.executemany("INSERT INTO users (user_id, username, reg_date, city, province) VALUES (%s, %s, %s, %s, %s)", users)

    # 插入订单
    orders = []
    order_id = 1
    current = start_date
    while current <= end_date:
        daily_orders = random.randint(50, 200)
        for _ in range(daily_orders):
            uid = random.randint(1, len(users))
            bid = random.randint(1, len(books))
            qty = random.randint(1, 5)
            price = books[bid-1][3]
            total = round(qty * price, 2)
            order_time = current + timedelta(
                hours=random.randint(0, 23),
                minutes=random.randint(0, 59),
                seconds=random.randint(0, 59)
            )
            orders.append((order_id, uid, bid, order_time, qty, total))
            order_id += 1
        current += timedelta(days=1)
    cursor.executemany(
        "INSERT INTO orders (order_id, user_id, book_id, order_date, quantity, total_price) VALUES (%s, %s, %s, %s, %s, %s)",
        orders
    )

    conn.commit()
    cursor.close()
    conn.close()
    print(f"✅ 模拟数据生成完成!共 {len(users)} 用户,{len(orders)} 订单。")

if __name__ == "__main__":
    insert_mock_data()

4️⃣ queries.py(所有数据查询逻辑)

python 复制代码
# queries.py
import mysql.connector
import pandas as pd
from config import DB_CONFIG

def get_db_connection():
    return mysql.connector.connect(**DB_CONFIG)

def sales_by_day_range(start_date, end_date):
    conn = get_db_connection()
    query = """
        SELECT DATE(order_date) AS date, SUM(quantity) AS total_qty
        FROM orders
        WHERE order_date BETWEEN %s AND %s
        GROUP BY DATE(order_date)
        ORDER BY date;
    """
    df = pd.read_sql(query, conn, params=[start_date, end_date])
    conn.close()
    return df.to_dict(orient='records')

def top_books_by_sales_range(start_date, end_date, limit=10):
    conn = get_db_connection()
    query = """
        SELECT b.title, SUM(o.quantity) AS total_sold
        FROM orders o
        JOIN books b ON o.book_id = b.book_id
        WHERE o.order_date BETWEEN %s AND %s
        GROUP BY b.book_id, b.title
        ORDER BY total_sold DESC
        LIMIT %s;
    """
    df = pd.read_sql(query, conn, params=[start_date, end_date, limit])
    conn.close()
    return df.to_dict(orient='records')

def new_users_by_week_range(start_date, end_date):
    conn = get_db_connection()
    query = """
        SELECT 
            YEARWEEK(reg_date, 1) AS week,
            COUNT(*) AS new_users
        FROM users
        WHERE reg_date BETWEEN %s AND %s
        GROUP BY week
        ORDER BY week;
    """
    df = pd.read_sql(query, conn, params=[start_date, end_date])
    conn.close()
    return df.to_dict(orient='records')

def sales_by_category_range(start_date, end_date):
    conn = get_db_connection()
    query = """
        SELECT b.category, SUM(o.quantity) AS total_qty
        FROM orders o
        JOIN books b ON o.book_id = b.book_id
        WHERE o.order_date BETWEEN %s AND %s
        GROUP BY b.category
        ORDER BY total_qty DESC;
    """
    df = pd.read_sql(query, conn, params=[start_date, end_date])
    conn.close()
    return df.to_dict(orient='records')

def sales_by_province_range(start_date, end_date):
    conn = get_db_connection()
    query = """
        SELECT u.province, SUM(o.quantity) AS total_qty
        FROM orders o
        JOIN users u ON o.user_id = u.user_id
        WHERE o.order_date BETWEEN %s AND %s
        GROUP BY u.province
        ORDER BY total_qty DESC;
    """
    df = pd.read_sql(query, conn, params=[start_date, end_date])
    conn.close()
    return df.to_dict(orient='records')

def get_kpi_range(start_date, end_date):
    conn = get_db_connection()
    query = """
        SELECT
            COUNT(DISTINCT user_id) AS total_users,
            COUNT(DISTINCT CASE WHEN user_order_count > 1 THEN user_id END) AS repeat_users,
            ROUND(AVG(total_per_user), 2) AS avg_order_value
        FROM (
            SELECT
                user_id,
                COUNT(*) AS user_order_count,
                SUM(total_price) AS total_per_user
            FROM orders
            WHERE order_date BETWEEN %s AND %s
            GROUP BY user_id
        ) AS user_stats;
    """
    df = pd.read_sql(query, conn, params=[start_date, end_date])
    conn.close()
    if df.empty or df.iloc[0]['total_users'] is None:
        return {"repeat_rate": 0, "avg_order_value": 0}
    total = df.iloc[0]['total_users'] or 1
    repeat = df.iloc[0]['repeat_users'] or 0
    aov = df.iloc[0]['avg_order_value'] or 0
    repeat_rate = round(repeat / total * 100, 2)
    return {"repeat_rate": repeat_rate, "avg_order_value": float(aov)}

5️⃣ app.py(Flask 主程序)

python 复制代码
# app.py
from flask import Flask, render_template, jsonify, request
from queries import (
    sales_by_day_range,
    top_books_by_sales_range,
    new_users_by_week_range,
    sales_by_category_range,
    sales_by_province_range,
    get_kpi_range
)

app = Flask(__name__)

@app.route('/')
def dashboard():
    return render_template('index.html')

@app.route('/api/sales-by-day')
def api_sales_by_day():
    start = request.args.get('start', '2025-01-01')
    end = request.args.get('end', '2025-12-31')
    return jsonify(sales_by_day_range(start, end))

@app.route('/api/top-books')
def api_top_books():
    start = request.args.get('start', '2025-01-01')
    end = request.args.get('end', '2025-12-31')
    return jsonify(top_books_by_sales_range(start, end))

@app.route('/api/new-users')
def api_new_users():
    start = request.args.get('start', '2025-01-01')
    end = request.args.get('end', '2025-12-31')
    return jsonify(new_users_by_week_range(start, end))

@app.route('/api/sales-by-category')
def api_sales_by_category():
    start = request.args.get('start', '2025-01-01')
    end = request.args.get('end', '2025-12-31')
    return jsonify(sales_by_category_range(start, end))

@app.route('/api/sales-by-province')
def api_sales_by_province():
    start = request.args.get('start', '2025-01-01')
    end = request.args.get('end', '2025-12-31')
    return jsonify(sales_by_province_range(start, end))

@app.route('/api/kpi')
def api_kpi():
    start = request.args.get('start', '2025-01-01')
    end = request.args.get('end', '2025-12-31')
    return jsonify(get_kpi_range(start, end))

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

6️⃣ templates/index.html(前端页面)

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>中信书店数据看板</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        .chart-container { height: 300px; margin-bottom: 20px; }
        .kpi-card { text-align: center; padding: 1.5rem; font-size: 1.5rem; }
    </style>
</head>
<body>
<div class="container mt-4">
    <h1 class="text-center mb-4">中信书店运营数据看板</h1>

    <!-- 时间筛选 -->
    <div class="row mb-4">
        <div class="col-md-5">
            <label>开始日期</label>
            <input type="date" id="startDate" class="form-control" value="2025-01-01">
        </div>
        <div class="col-md-5">
            <label>结束日期</label>
            <input type="date" id="endDate" class="form-control" value="2025-12-31">
        </div>
        <div class="col-md-2 d-flex align-items-end">
            <button class="btn btn-primary w-100" onclick="refreshData()">刷新</button>
        </div>
    </div>

    <!-- KPI 卡片 -->
    <div class="row mb-4">
        <div class="col-md-6">
            <div class="card bg-light">
                <div class="kpi-card">
                    <div>复购率</div>
                    <div id="repeatRate">--%</div>
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="card bg-light">
                <div class="kpi-card">
                    <div>客单价</div>
                    <div id="avgOrderValue">¥--</div>
                </div>
            </div>
        </div>
    </div>

    <!-- 图表区域 -->
    <div class="row">
        <div class="col-md-6">
            <div class="card"><div class="card-header">📅 每日销量(册)</div><div class="card-body"><canvas id="salesChart"></canvas></div></div>
        </div>
        <div class="col-md-6">
            <div class="card"><div class="card-header">📚 销量Top10书籍</div><div class="card-body"><canvas id="topBooksChart"></canvas></div></div>
        </div>
    </div>

    <div class="row">
        <div class="col-md-6">
            <div class="card"><div class="card-header">👥 每周新增用户</div><div class="card-body"><canvas id="newUsersChart"></canvas></div></div>
        </div>
        <div class="col-md-6">
            <div class="card"><div class="card-header">📊 品类销量分布</div><div class="card-body"><canvas id="categoryChart"></canvas></div></div>
        </div>
    </div>

    <div class="row">
        <div class="col-12">
            <div class="card"><div class="card-header">📍 各省份销量分布</div><div class="card-body"><canvas id="provinceChart"></canvas></div></div>
        </div>
    </div>
</div>

<script>
let currentStart = '2025-01-01';
let currentEnd = '2025-12-31';
window.charts = {};

function buildUrl(endpoint) {
    return `${endpoint}?start=${currentStart}&end=${currentEnd}`;
}

async function loadKPI() {
    const res = await fetch(buildUrl('/api/kpi'));
    const data = await res.json();
    document.getElementById('repeatRate').textContent = data.repeat_rate + '%';
    document.getElementById('avgOrderValue').textContent = '¥' + data.avg_order_value;
}

function refreshData() {
    currentStart = document.getElementById('startDate').value;
    currentEnd = document.getElementById('endDate').value;
    loadAllCharts();
}

async function loadAllCharts() {
    loadKPI();

    const configs = {
        'salesChart': {
            type: 'line',
            data: {
                labels: [],
                datasets: [{ label: '销量(册)', data: [], borderColor: 'rgb(75,192,192)', tension: 0.1 }]
            }
        },
        'topBooksChart': {
            type: 'bar',
            data: {
                labels: [],
                datasets: [{ label: '总销量', data: [], backgroundColor: 'rgba(54,162,235,0.6)' }]
            },
            options: { indexAxis: 'y' }
        },
        'newUsersChart': {
            type: 'line',
            data: {
                labels: [],
                datasets: [{ label: '新增用户', data: [], borderColor: 'rgb(255,99,132)' }]
            }
        },
        'categoryChart': {
            type: 'pie',
            data: {
                labels: [],
                datasets: [{ data: [], backgroundColor: ['#FF6384','#36A2EB','#FFCE56','#4BC0C0','#9966FF'] }]
            }
        },
        'provinceChart': {
            type: 'bar',
            data: {
                labels: [],
                datasets: [{ label: '销量(册)', data: [], backgroundColor: 'rgba(153,102,255,0.6)' }]
            }
        }
    };

    const endpoints = {
        'salesChart': '/api/sales-by-day',
        'topBooksChart': '/api/top-books',
        'newUsersChart': '/api/new-users',
        'categoryChart': '/api/sales-by-category',
        'provinceChart': '/api/sales-by-province'
    };

    for (const [chartId, config] of Object.entries(configs)) {
        const res = await fetch(buildUrl(endpoints[chartId]));
        const data = await res.json();

        if (chartId === 'salesChart') {
            config.data.labels = data.map(d => d.date);
            config.data.datasets[0].data = data.map(d => d.total_qty);
        } else if (chartId === 'topBooksChart') {
            config.data.labels = data.map(d => d.title.length > 12 ? d.title.slice(0,10)+'...' : d.title);
            config.data.datasets[0].data = data.map(d => d.total_sold);
        } else if (chartId === 'newUsersChart') {
            config.data.labels = data.map(d => 'W' + (d.week % 100));
            config.data.datasets[0].data = data.map(d => d.new_users);
        } else if (chartId === 'categoryChart') {
            config.data.labels = data.map(d => d.category);
            config.data.datasets[0].data = data.map(d => d.total_qty);
        } else if (chartId === 'provinceChart') {
            config.data.labels = data.map(d => d.province);
            config.data.datasets[0].data = data.map(d => d.total_qty);
        }

        const ctx = document.getElementById(chartId).getContext('2d');
        if (window.charts[chartId]) window.charts[chartId].destroy();
        config.options = { ...config.options, responsive: true, maintainAspectRatio: false };
        window.charts[chartId] = new Chart(ctx, config);
    }
}

loadAllCharts();
</script>
</body>
</html>

▶️ 使用步骤(小白友好)

  1. 确保 MySQL 已安装,并创建数据库:

    sql 复制代码
    CREATE DATABASE zx_book CHARACTER SET utf8mb4;
  2. 安装 Python 依赖

    bash 复制代码
    pip install -r requirements.txt
  3. 生成模拟数据(只需运行一次):

    bash 复制代码
    python generate_mock_data.py

运行成功输出如下

bash 复制代码
python generate_mock_data.py 

✅ 模拟数据生成完成!共 7312 用户,45740 订单。
  1. 启动 Web 服务
bash 复制代码
  python app.py
  1. 打开浏览器,访问:
bash 复制代码
  http://localhost:5000

完整的前后端数据库交互案例就有了,这是很基础的一个版本,更加丰富的功能,可以让大模型帮助我们逐步完善

  • 浏览器前端网页效果如下:

📦 学习阶段五:各种丰富的多表联合 - 增删改查

  • 进阶成为高级 - 资深 数据分析砖家
  • 跟着 XX 大模型学习即可

❤️ 一起学习用 AI 创造可能


  • ❤️ 如果文章对你有些许帮助、蟹蟹各位读者大大点赞、评论鼓励博主的每一分认真创作
相关推荐
数研小生5 小时前
亚马逊商品列表API详解
前端·数据库·python·pandas
独好紫罗兰5 小时前
对python的再认识-基于数据结构进行-a005-元组-CRUD
开发语言·数据结构·python
洛豳枭薰5 小时前
MySQL 并行复制
数据库·mysql
纤纡.5 小时前
Linux 下 MySQL 数据类型与约束:第三章核心表格归纳与实战应用
linux·mysql
jianghua0015 小时前
Python中的简单爬虫
爬虫·python·信息可视化
czlczl200209255 小时前
增删改查时如何提高Mysql与Redis的一致性
数据库·redis·mysql
打工的小王5 小时前
MySql(二)索引
数据库·mysql
喵手5 小时前
Python爬虫实战:针对Python官网,精准提取出每一个历史版本的版本号、发布日期以及对应的文档/详情页链接等信息,并最终清洗为标准化的CSV文件!
爬虫·python·爬虫实战·零基础python爬虫教学·python官方数据采集·采集历史版本版本号等信息·导出csv文件
databook5 小时前
像搭积木一样思考:数据科学中的“自下而上”之道
python·数据挖掘·数据分析