You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python定时从SQL Server导出数据时如何避免重复获取?

无需修改数据表的SQL Server增量数据获取方案

下面提供几种无需修改目标数据表的实现思路,按推荐优先级排序:


1. 基于时间戳字段(优先推荐,若表存在创建/更新时间列)

如果你的数据表本身带有create_time或update_time这类记录数据生成时间的字段,可以通过记录上次运行时的最新时间,每次查询仅获取该时间之后的新增数据。

实现步骤:

  • 用本地文件存储上次获取到的最大时间戳
  • 首次运行时获取全量数据,并记录数据中的最大时间戳
  • 后续运行时,仅查询时间戳大于上次记录值的数据
  • 更新本地存储的时间戳为本次获取到的最大时间戳

代码示例:

import pyodbc
import datetime
import os

# 存储上次运行时间戳的文件
LAST_TIMESTAMP_FILE = "last_fetch_timestamp.txt"

def load_last_timestamp():
    if os.path.exists(LAST_TIMESTAMP_FILE):
        with open(LAST_TIMESTAMP_FILE, "r") as f:
            return datetime.datetime.fromisoformat(f.read().strip())
    return None

def save_last_timestamp(timestamp):
    with open(LAST_TIMESTAMP_FILE, "w") as f:
        f.write(timestamp.isoformat())

def fetch_incremental_data():
    # 建立SQL Server连接
    conn_str = "DRIVER={SQL Server};SERVER=你的服务器地址;DATABASE=你的数据库;UID=用户名;PWD=密码"
    conn = pyodbc.connect(conn_str)
    cursor = conn.cursor()

    last_ts = load_last_timestamp()
    current_max_ts = None

    if last_ts is None:
        # 首次运行,拉取全量数据
        print("首次运行,获取全量数据")
        cursor.execute("SELECT * FROM 你的表名")
    else:
        # 增量拉取,筛选时间戳大于上次记录的数据
        print(f"增量获取自 {last_ts} 之后的新数据")
        cursor.execute("SELECT * FROM 你的表名 WHERE create_time > ?", (last_ts,))

    # 获取并处理数据
    rows = cursor.fetchall()
    for row in rows:
        # 这里替换成你的数据处理逻辑(如写入文件、分析等)
        print(row)

    # 更新本次获取的最大时间戳
    cursor.execute("SELECT MAX(create_time) FROM 你的表名")
    current_max_ts = cursor.fetchone()[0]
    if current_max_ts:
        save_last_timestamp(current_max_ts)
    else:
        # 表为空时,用当前时间作为初始标记
        save_last_timestamp(datetime.datetime.now())

    conn.close()

if __name__ == "__main__":
    fetch_incremental_data()

2. 基于自增主键/唯一递增标识

如果数据表有自增ID(如id INT IDENTITY(1,1))或其他严格递增的唯一字段,可以通过记录上次获取到的最大ID值,后续仅查询ID大于该值的数据。

代码示例:

import pyodbc
import os

# 存储上次获取的最大ID的文件
LAST_ID_FILE = "last_fetch_max_id.txt"

def load_last_max_id():
    if os.path.exists(LAST_ID_FILE):
        with open(LAST_ID_FILE, "r") as f:
            return int(f.read().strip())
    return None

def save_last_max_id(max_id):
    with open(LAST_ID_FILE, "w") as f:
        f.write(str(max_id))

def fetch_incremental_data():
    conn_str = "DRIVER={SQL Server};SERVER=你的服务器地址;DATABASE=你的数据库;UID=用户名;PWD=密码"
    conn = pyodbc.connect(conn_str)
    cursor = conn.cursor()

    last_max_id = load_last_max_id()
    current_max_id = None

    if last_max_id is None:
        print("首次运行,获取全量数据")
        cursor.execute("SELECT * FROM 你的表名")
    else:
        print(f"增量获取ID大于 {last_max_id} 的新数据")
        cursor.execute("SELECT * FROM 你的表名 WHERE id > ?", (last_max_id,))

    rows = cursor.fetchall()
    for row in rows:
        print(row)

    # 更新本次获取的最大ID
    cursor.execute("SELECT MAX(id) FROM 你的表名")
    current_max_id = cursor.fetchone()[0]
    if current_max_id:
        save_last_max_id(current_max_id)

    conn.close()

if __name__ == "__main__":
    fetch_incremental_data()

3. 无时间戳/自增ID时的兜底方案(小表适用)

如果数据表既没有时间戳也没有递增标识,只能通过记录已获取过的记录的唯一特征(如多字段组合的唯一键),每次拉取全量数据后对比筛选新增记录。注意:此方法效率较低,仅适合数据量较小的表。

代码示例:

import pyodbc
import os
import pickle

# 存储已获取记录唯一标识的文件
FETCHED_RECORDS_FILE = "fetched_records.pkl"

def load_fetched_records():
    if os.path.exists(FETCHED_RECORDS_FILE):
        with open(FETCHED_RECORDS_FILE, "rb") as f:
            return pickle.load(f)
    return set()

def save_fetched_records(records_set):
    with open(FETCHED_RECORDS_FILE, "wb") as f:
        pickle.dump(records_set, f)

def fetch_incremental_data():
    conn_str = "DRIVER={SQL Server};SERVER=你的服务器地址;DATABASE=你的数据库;UID=用户名;PWD=密码"
    conn = pyodbc.connect(conn_str)
    cursor = conn.cursor()

    fetched_records = load_fetched_records()
    current_records = set()
    new_rows = []

    # 拉取全量数据
    cursor.execute("SELECT col1, col2, col3 FROM 你的表名")
    all_rows = cursor.fetchall()

    # 生成唯一标识并筛选新增记录(这里用col1+col2作为唯一键,根据实际表结构调整)
    for row in all_rows:
        record_key = f"{row[0]}_{row[1]}"
        current_records.add(record_key)
        if record_key not in fetched_records:
            new_rows.append(row)

    if not fetched_records:
        print("首次运行,获取全量数据")
    else:
        print(f"增量获取 {len(new_rows)} 条新数据")

    for row in new_rows:
        print(row)

    # 更新已获取记录的标识集合
    save_fetched_records(current_records)

    conn.close()

if __name__ == "__main__":
    fetch_incremental_data()

注意事项:

  • 本地存储的标记文件(如时间戳、ID文件)需确保权限正常,避免被误删除
  • 时间戳方案需注意SQL Server与Python运行环境的时区一致性,避免漏取或重复获取数据
  • 若脚本运行间隔较长,需确保期间没有数据被删除(如果需要处理删除的记录,此方案不适用)

内容的提问来源于stack exchange,提问作者Sai ganesh Dokala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 00:06:25