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

Python如何编写合适的while循环 等待MSSQL触发器触发后拉取数据发送Telegram

核心问题定位

你的代码运行后直接退出,本质是几个逻辑层面的根本性错误导致的:

  • 完全误解MSSQL触发器的运行机制:触发器是数据库内部的事件响应逻辑,执行后不会主动向Python连接返回结果集。你在循环中反复执行CREATE TRIGGER语句,第一次运行就会因触发器对象已存在触发报错,根本无法获取到任何数据。
  • 循环判断逻辑完全失效:你初始将row设置为字符串'0',但CREATE TRIGGER属于数据定义类操作,不会生成可返回的结果集,cursor.fetchone()会直接返回None,循环条件瞬间不成立,进程直接退出。
  • 结构变更类操作(建表、建触发器)不需要放在运行时循环中执行,这类操作仅需提前在数据库中执行一次即可长期生效。
正确实现思路

要实现“触发器识别到符合条件的插入记录后,Python脚本拉取数据并推送至Telegram”的需求,最稳定易维护的方案是结合数据库触发器+长驻轮询:

  1. 提前在数据库中创建一张待处理通知表,用来存储触发器识别到的、需要推送的业务数据。
  2. 在业务表上配置触发器,当有新插入记录时,将符合筛选、关联规则的数据自动写入待处理通知表。
  3. Python脚本长驻运行,每隔固定时间查询待处理表中未标记为已推送的记录,拿到数据后调用Telegram接口发消息,再将对应记录标记为已处理,避免重复推送。
修正步骤与代码

第一步:提前在MSSQL中执行数据库结构配置

注意:这段SQL仅需在数据库中运行一次,不要放到Python的运行循环中执行:

-- 新建待推送通知表
CREATE TABLE dbo.PendingTelegramNotify(
    NotifyID bigint IDENTITY(1,1) PRIMARY KEY,
    TimeVal datetime,
    Remark nvarchar(200),
    Name nvarchar(100),
    FirstName nvarchar(100),
    IsProcessed bit DEFAULT 0
)
GO

-- 创建关联业务表的触发器
CREATE OR ALTER TRIGGER Server_enter
ON pLogData
AFTER INSERT
AS
BEGIN
    -- 关闭冗余的行数返回提示,避免干扰应用读取数据
    SET NOCOUNT ON;
    -- 关联本次插入的临时表,仅拉取本次新插入的对应数据
    INSERT INTO dbo.PendingTelegramNotify(TimeVal, Remark, Name, FirstName)
    SELECT [TimeVal],[Remark],[Name],[FirstName]
    FROM [data1]
    INNER JOIN [data2] 
        ON [ID] = [ID]
    -- 必须关联系统临时表inserted,匹配本次新插入的pLogData记录,否则会全表重复写入
    INNER JOIN inserted 
        ON inserted.关联外键 = data2.对应ID字段 -- 此处替换为你实际的表关联外键
    WHERE [Remark] LIKE '%server%'
END
GO

第二步:Python长驻脚本实现

import pymssql
import time
import requests

# 数据库连接配置
DB_CONFIG = {
    "server": "serv",
    "user": "user",
    "password": "pwd",
    "database": "DB"
}
# Telegram机器人配置
TELEGRAM_BOT_TOKEN = "你的Telegram机器人Token"
TELEGRAM_RECEIVER_CHAT_ID = "接收消息的Chat ID"

def get_db_connection():
    """获取数据库连接,每次断开重连时调用"""
    return pymssql.connect(**DB_CONFIG)

def push_to_telegram(content):
    """调用Telegram接口推送消息"""
    api_endpoint = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
    requests.post(api_endpoint, json={
        "chat_id": TELEGRAM_RECEIVER_CHAT_ID,
        "text": content
    })

if __name__ == "__main__":
    print("数据库连接成功,开始监听待推送事件")
    db_conn = get_db_connection()
    # 无限循环保持脚本运行
    while True:
        try:
            with db_conn.cursor() as cursor:
                # 查询所有未处理的待推送记录
                cursor.execute("""
                    SELECT NotifyID, TimeVal, Remark, Name, FirstName
                    FROM PendingTelegramNotify
                    WHERE IsProcessed = 0
                """)
                pending_rows = cursor.fetchall()
                if pending_rows:
                    for row in pending_rows:
                        notify_id, event_time, remark, name, first_name = row
                        message = f"检测到服务器事件触发:\n事件时间:{event_time}\n备注:{remark}\n相关人员:{first_name} {name}"
                        push_to_telegram(message)
                        # 将当前记录标记为已处理,避免重复推送
                        cursor.execute("""
                            UPDATE PendingTelegramNotify
                            SET IsProcessed = 1
                            WHERE NotifyID = %s
                        """, (notify_id,))
                    # 提交事务,确保更新生效
                    db_conn.commit()
            # 循环间隔2秒,避免过度占用数据库资源
            time.sleep(2)
        except Exception as e:
            print(f"运行异常:{e}")
            # 异常后断开旧连接,等待5秒重新建立连接
            db_conn.close()
            time.sleep(5)
            db_conn = get_db_connection()
关键注意事项
  • 循环中必须加入time.sleep()控制轮询间隔,否则脚本会以满CPU状态高频查询数据库,耗尽数据库服务资源。
  • 必须做好连接异常重连逻辑,避免网络波动、数据库临时重启导致脚本直接退出。
  • 触发器中必须关联MSSQL内置的inserted临时表,否则每次新插入日志记录时,会将全表所有符合筛选条件的记录重复写入待推送表,造成大量重复消息。
  • 触发器中的SET NOCOUNT ON必须保留,否则数据库会返回冗余的行数提示,导致pymssql读取结果集时出现错乱。

内容的提问来源于stack exchange,提问作者Bardysya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 07:15:05