oracle使用cursor动态更新线上初始化数据

本文介绍了一个使用PL/SQL实现的批量数据更新案例。通过声明游标和循环遍历的方式,动态调整了数据表中特定记录的PRESENT_NUM和PRESENT_LEFT_NUM字段值,并实现了每处理100条记录提交一次的批处理逻辑。

背景:线上系统初始化数据需要调整,同时剩余数量也需要动态的调整

DECLARE
CURSOR c_res
IS SELECT B.PRESENT_NAME,B.PRESENT_PRESENT_LEFT_NUM,B.PRESENT_NUM FROM table B;
commitsum NUMBER(10);
leftNum NUMBER(4);
presentNum NUMBER(4);
BEGIN
commitsum :=0;
presentNum:=0;
FOR r_res IN c_res
LOOP
 commitsum :=commitsum+1;
leftNum:=r_res.PRESENT_NUM-r_res.PRESENT_LEFT_NUM;
CASE
 WHEN r_res.PRESENT_NAME='1';
THEN presentNum=100;
WHEN  r_res.PRESENT_NAME='2';
THEN presentNum=200;
END CASE;
UPDATE table set PRESENT_NUM=presentNum,PRESENT_LEFT_NUM = presentNum-leftNum
WHERE PRESENT_NAME = r_res.PRESENT_NAME;
IF(commitsum>100)
THEN 
COMMIT;
commitsum:=0;
END IF;
END LOOP;
COMMIT;
END;


# -*- coding: utf-8 -*- import os import cx_Oracle as cx import pandas as pd import datetime as dt import warnings import time from threading import Thread import schedule from openpyxl import load_workbook from openpyxl.utils.dataframe import dataframe_to_rows import requests import base64 import hashlib from PIL import ImageGrab import win32com.client as win32 import pythoncom warnings.filterwarnings('ignore') class Wechat: def __init__(self, secret): self.secret = secret def access_token(self): """获取企业微信access_token""" url = f'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=wwed5e7f3fd1a3a553&corpsecret={self.secret}' response = requests.get(url).json() return response['access_token'] def oracle_connect(sql): """Oracle数据库连接查询""" con = cx.connect("admin/xxb20140415@192.168.3.16:1521/zzjdata") cursor = con.cursor() cursor.execute(sql) column_s = [col[0] for col in cursor.description] data = cursor.fetchall() cursor.close() con.close() return data, column_s def generate_g3_monthly_sql(): """生成月度G3阶段销售数据查询SQL""" sql = """ ------阶段销售查询表(按门店)(月度) with hzxs as (select a.subbh,a.hedgehh,a.sl,a.lsh,a.jshj,a.ml,a.hh,a.ph1_xq,a.posguid,a.xsr from subfhd a left join gl_custom b on a.subbh=b.tjbh where a.kdrq between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and nvl(a.bz,' ')<>'会员礼品成本调整单' and nvl(a.bz,' ')<>'¥' and nvl(a.bm,' ')<>'积分兑换' and b.tj_tag<>'40'), abc as (select b.tjbh,f.hh,a.PRODUCTTYPE,a.PRODUCTSUBTYPE,a.FEETYPE1,a.productid,sum(a.amount) jshj from abc_feedetail a left join gl_custom b on a.CLINICID=b.C_ABCID left join yw_kck f on a.productid=f.c_abcgoodsid where to_date(substr(a.created,1,10),'yyyy-mm-dd') between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by b.tjbh,f.hh,a.PRODUCTTYPE,a.PRODUCTSUBTYPE,a.FEETYPE1,a.productid), xs as (select subbh,sum(jshj) jshj,sum(ml) ml,count(distinct lsh) kds from hzxs group by subbh union select a.tjbh,nvl(a.jshj,0)-nvl(d.jshj,0) jshj,nvl(c.ml,0)+nvl(b.ml,0) ml,a.kds from (select b.tjbh,sum(a.amount) jshj,count(distinct TRANSACTIONID) kds from abc_feebill a left join gl_custom b on a.CLINICID=b.C_ABCID where to_date(substr(a.created,1,10),'yyyy-mm-dd') between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by b.tjbh) a left join (select c.tjbh,sum(case when a.action='退药' then -a.saleprice else a.saleprice end)+sum(a.costprice) ml from ABC_INOUTSTOCK a left join gl_custom c on a.clinicid=c.c_abcid where a.action in ('发药','退药') and to_date(substr(a.fdate,1,10),'yyyy-mm-dd') between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by c.tjbh) c on a.tjbh=c.tjbh left join (select tjbh,sum(jshj) ml from abc where producttype not in ('1','2','7') and productid not in ('00000000000000000000000000000007','00000000000000000000000000000003','00000000000000000000000000000004','00000000000000000000000000000008', '00000000000000000000000000000010') group by tjbh) b on a.tjbh=b.tjbh left join (select tjbh,sum(jshj) jshj from abc where FEETYPE1 like '%充值%' group by tjbh) d on a.tjbh=d.tjbh ), zyy as (select a.subbh,sum(a.jshj) jshj from hzxs a inner join yw_kck b on a.hedgehh=b.hh left join gl_ryk c on a.xsr=c.dh where b.fzflsx1='08'group by a.subbh union select tjbh,sum(jshj) jshj from abc where FEETYPE1<>'西药' and FEETYPE1<>'中成药'and FEETYPE1<>'卡项充值本金' and FEETYPE1<>'会员充值本金' group by tjbh ), --zyml as (select subbh,abs(sum(ml)) ml from hzxs where ml<0 and sl>0 and hedgehh in (select hh from c_zkmdbmlpzmx) group by subbh), rw as (select a.subbh,round(nvl(a.yxse*(b.xsxs/100),0),0) xsrw,round(a.ymle*(d.xsxs/100),0) mlrw,round(nvl(a.ybbxse*(c.xsxs/100),0),0) tyrw from (select subbh,yxse,ybbxse,ymle from c_mdjyys where nd='0' and yf='0') a left join (select a.rwlb,sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='绩效销售额任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by a.rwlb) b on 1=1 left join (select a.rwlb,sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='月毛利额任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by a.rwlb) d on 1=1 left join (select a.rwlb,sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='特药任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by a.rwlb) c on 1=1), zyrw as (select a.subbh,a.pzlb,a.rwje*(b.xsxs/100) rwje from (select * from c_zbjlrwzk where nd='0' and yf='0' and pzlb='中药任务') a left join (select sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='中药任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)) b on 1=1), nfrw as (select a.subbh,a.pzlb,a.rwje*(b.xsxs/100) rwje from (select * from c_zbjlrwzk where nd='0' and yf='0' and pzlb='膏方任务') a left join (select sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='膏方任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)) b on 1=1), gfrw as (select a.subbh,a.pzlb,a.rwje*(b.xsxs/100) rwje from (select * from c_zbjlrwzk where nd='0' and yf='0' and pzlb='内方基础任务') a left join (select sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='内方任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)) b on 1=1), zdpzrw as (select a.subbh,a.pzlb,a.rwje*(b.xsxs/100) rwje from (select * from c_zbjlrwzk where nd='0' and yf='0' and pzlb='重点品种任务') a left join (select sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='重点品种任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)) b on 1=1), zdpz as (select b.subbh,sum(b.jshj) jshj from (select a.code,b.hh,b.sx from organization a left join spjxlbz b on a.SPJXFLZ=b.lbz where b.sx='A+' OR b.sx='B' OR b.sx='A'OR b.sx='D+') a inner join (select subbh,hedgehh,jshj,lsh from hzxs union all select tjbh,hh,jshj,' ' from abc ) b on a.code=b.subbh and a.hh=b.hedgehh group by b.subbh), gfxs as (select a.subbh,sum(a.jshj) jshj from hzxs a left join yw_kck b on a.hedgehh=b.hh where nvl(a.posguid,' ')='10001' or b.fzflsx2='08042' group by a.subbh), xsfl as (select a.*,c.sx from (select subbh,hedgehh,jshj,ml,lsh from hzxs union all select tjbh,hh,jshj,0,' ' from abc ) a left join(select * from spjxlbz where lbz='1') c on a.hedgehh=c.hh) select a.c_mdfq 大区,a.c_mdfq1 地区,a.tjbh 门店编号,a.mc 门店名称,nvl(b.xsrw,0)+nvl(b.tyrw,0) 总销售任务,c.jshj 总销售额,b.mlrw 毛利任务,nvl(c.ml,0)-nvl(y6.ml,0) 毛利额,k.rwje 重点品种任务,nvl(e.jshj,0)+nvl(i.jshj,0) 重点品种销售, j.jshj 中医药销售,to_char(a.c_kykdrq,'yyyy-mm-dd') 开业日期,case when t1.SPJXFLZ='1' then '郑州市' when t1.SPJXFLZ='2' then '外地市' when t1.SPJXFLZ='3' then '县乡镇' else ' ' end 地域类型,round((nvl(f.rwje,0)+nvl(g.rwje,0)+nvl(h.rwje,0)),2) 中医药任务, case when nvl(b.mlrw,0)<>0 then round( (nvl(c.ml,0)-nvl(y6.ml,0))*100/b.mlrw,2) else 0 end 毛利进度,nvl(x.jshj,0) 线下销售额,nvl(x.kds,0) 线下客单,nvl(c.kds,0) 总客流, case when nvl(k.rwje,0)<>0 then round((nvl(e.jshj,0)+nvl(i.jshj,0))*100/k.rwje,2) else 0 end 重点品种进度,case when nvl(b.tyrw,0)=0 then 0 else nvl(y6.jshj,0) end 特药销售,b.tyrw 特药任务, case when nvl(b.tyrw,0)<>0 then round((case when nvl(b.tyrw,0)=0 then 0 else nvl(y6.jshj,0) end)*100/b.tyrw,2) else 0 end 特药完成进度, nvl(b.xsrw,0) 非特药任务, case when nvl(b.tyrw,0)=0 then nvl(c.jshj,0) else nvl(c.jshj,0)-nvl(y6.jshj,0) end 非特药销售,case when nvl(b.xsrw,0)<>0 then round((case when nvl(b.tyrw,0)=0 then nvl(c.jshj,0) else nvl(c.jshj,0)-nvl(y6.jshj,0) end)*100/nvl(b.xsrw,0),2) else 0 end 非特药完成进度 from gl_custom a left join rw b on a.tjbh=b.subbh left join xs c on a.tjbh=c.subbh left join zyrw f on a.tjbh=f.subbh left join nfrw g on a.tjbh=g.subbh left join gfrw h on a.tjbh=h.subbh left join zyy j on a.tjbh=j.subbh left join zdpz e on a.tjbh=e.subbh left join gfxs i on a.tjbh=i.subbh left join zdpzrw k on a.tjbh=k.subbh left join organization t1 on a.tjbh=t1.code left join (select subbh,sum(jshj) jshj,sum(ml) ml,count(distinct lsh) kds from hzxs where nvl(posguid,' ')<>'10000' group by subbh) x on a.tjbh=x.subbh left join (select subbh,sum(jshj) jshj from xsfl where sx = 'A+' group by subbh) y1 on a.tjbh=y1.subbh left join (select subbh,sum(jshj) jshj from xsfl where sx = 'C+' group by subbh) y2 on a.tjbh=y2.subbh left join (select subbh,sum(jshj) jshj from xsfl where sx = 'A' group by subbh) y3 on a.tjbh=y3.subbh left join (select subbh,sum(jshj) jshj from xsfl where sx = 'B' group by subbh) y4 on a.tjbh=y4.subbh left join (select subbh,sum(jshj) jshj from xsfl where sx = 'C' OR sx = 'C ' group by subbh) y5 on a.tjbh=y5.subbh left join (select subbh,sum(jshj) jshj,sum(ml) ml from xsfl where sx = 'D' group by subbh) y6 on a.tjbh=y6.subbh left join (select subbh,sum(jshj) jshj from xsfl where sx = 'E' group by subbh) y7 on a.tjbh=y7.subbh left join (select subbh,sum(jshj) jshj from xsfl where sx = 'F' OR sx = 'f' group by subbh) y8 on a.tjbh=y8.subbh where a.c_mdfq is not null and (a.tj_tag='14' or a.tj_tag='40') --and a.mc like '%仲景生活%' and nvl(a.C_STORETYPE, '0') = '1' """ return sql def generate_g3_weekly_sql(): """生成月度G3周度销售数据查询SQL""" sql = """ ---------仲景生活周度数据通报(月度) select b.TJBH as 门店编号,b.mc as 门店名称,TRUNC(a.kdrq) as 日期,d.name as 零售小类,a.hh as 货号,c.pm as 品名,sum(a.SL) as 数量 ,sum(a.jshj) as 销售额,case when nvl(sum(SL),0)<>0 then round(sum(cbe) / sum(SL), 2) else 0 end as 成本价, sum(a.ML) as 毛利, case when nvl(sum(a.JSHJ),0)<>0 then round(sum(ml) / sum(JSHJ), 2) else 0 end as 毛利率,c.hyj as 会员价,c.lsj as 零售价 from subfhd a left join gl_custom b on a.subbh=b.tjbh left join yw_kck c on a.hh = c.HH left join dataitem d on c.FZFLSX3 = d.CODE where a.kdrq between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and nvl(a.bz,' ')<>'会员礼品成本调整单' and nvl(a.bz,' ')<>'¥' and nvl(a.bm,' ')<>'积分兑换' and b.tj_tag<>'40' and nvl(b.C_STORETYPE, '0') = '1' group by b.TJBH, b.mc, TRUNC(a.kdrq), d.name, a.hh, c.pm, c.lsj, c.hyj order by b.tjbh, TRUNC(a.kdrq) """ return sql def generate_g3_daily_monthly_sql(): """生成月度G3每日销售数据查询SQL""" sql = """ ------门店每日总销售额(月度) select a.kdrq 日期,a.subbh 门店编码,a.mc 门店名称,a.jshj 价税合计,nvl(a.jshj-dx.dxje,a.jshj) 总销售额,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/j.xxkl,2) 线下客单价,nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0) 线下价税合计, (case when nvl(a.jshj,0)=0 then 0 else round(a.hsmle/a.jshj,4) end) 毛利率,sum(a.khs) 客户数,sum(a.hykds) 会员客单数,sum((case when nvl(a.khs,0)=0 then 0 else round(nvl(a.jshj,0)/a.khs,4) end)) 客单价,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) 线上销售额占比, a.hsmle 毛利额,a.hyxse 会员销售额,dx.dxje 积分抵现金额,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/i.xskl,2) 线上客单价,nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0) 线上价税合计, (case when nvl(a.jshj,0)=0 then 0 else 100*round(nvl(a.hyxse,0)/a.jshj,4) end) 会员销售占比,b.hyqb 会员钱包销售额,xs.fkje 惜食小程序,d.fkje 饿了么,c.fkje 美团外卖,f.fkje 美团点评,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) 线下销售额占比, h.fkje 收钱吧,g.fkje 抖音团购,i.xskl 线上客单数,j.xxkl 线下客单数 from ( select a.kdrq kdrq,b.mc mc,a.subbh subbh,ROUND(sum(a.jshj),2) jshj,sum(c.sj1) sj1, count(distinct a.lsh) as khs,count(distinct case when nvl(a.YHKH,' ')<>' ' then a.lsh else ' ' end) hykds, sum(case when nvl(a.yhkh,' ')<>' ' then a.jshj else 0 end) hyxse, sum(a.ml) hsmle,sum(a.ml) ml from subfhd a right join (select * from gl_custom where nvl(c_storetype,0)=1) b on a.subbh=b.tjbh right join (select * from yw_kck ) c on a.hh=c.hh where a.Kdrq between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and nvl(a.bz,' ')<>'会员礼品成本调整单' and nvl(a.bz,' ')<>'¥' group by a.subbh,a.kdrq,b.mc ) a left join (select kdrq,subbh,sum(jshj) dxje from subfhd where kdrq between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and hh='JFDX' group by subbh, kdrq ) dx on (a.subbh=dx.subbh and a.kdrq=dx.kdrq) left join ( select a.KDRQ,a.subbh,sum(a.fkje) hyqb from subdfkfs a inner join (select tjbh from gl_custom where nvl(c_storetype,0)=1) b on a.subbh=b.tjbh where a.fkfsid='hyqb' and KDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by a.subbh,a.KDRQ ) b on (a.subbh=b.subbh and a.kdrq=b.kdrq) left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('SY-MTWM') group by SUBBH, KDRQ) c on a.subbh=c.subbh and a.kdrq=c.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('SYELM') group by SUBBH, KDRQ) d on a.subbh=d.subbh and a.kdrq=d.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('197') group by SUBBH, KDRQ) f on a.subbh=f.subbh and a.kdrq=f.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('801') group by SUBBH, KDRQ) g on a.subbh=g.subbh and a.kdrq=g.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('806') group by SUBBH, KDRQ) h on a.subbh=h.subbh and a.kdrq=h.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('215') group by SUBBH, KDRQ) xs on a.subbh=xs.subbh and a.kdrq=xs.kdrq left join (select SUBBH, KDRQ,count(distinct xhlsh) xskl from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('SY-MTWM','SYELM','197','801','808','215') group by SUBBH, KDRQ) i on a.subbh=i.subbh and a.kdrq=i.kdrq left join (select SUBBH, KDRQ,count(distinct xhlsh) xxkl from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid not in ('SY-MTWM','SYELM','197','801','808','215') group by SUBBH, KDRQ) j on a.subbh=j.subbh and a.kdrq=j.kdrq group by a.subbh, a.mc, a.kdrq, a.jshj, a.hsmle,a.ml,b.hyqb,a.hyxse, (case when nvl(a.jshj,0)=0 then 0 else round(a.hsmle/a.jshj,4) end), dx.dxje, nvl(a.jshj-dx.dxje,a.jshj), (case when nvl(a.jshj,0)=0 then 0 else 100*round(nvl(a.hyxse,0)/a.jshj,4) end),c.fkje,d.fkje,f.fkje,g.fkje,h.fkje,xs.fkje,nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0) ,nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0) ,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) ,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) ,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/i.xskl,2) ,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/j.xxkl,2),i.xskl,j.xxkl order by a.subbh """ return sql def generate_g3_daily_yesterday_sql(): """生成昨日G3每日销售数据查询SQL""" sql = """ ------门店每日总销售额(昨日) select a.kdrq 日期,a.subbh 门店编码,a.mc 门店名称,a.jshj 价税合计,nvl(a.jshj-dx.dxje,a.jshj) 总销售额,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/j.xxkl,2) 线下客单价,nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0) 线下价税合计, (case when nvl(a.jshj,0)=0 then 0 else round(a.hsmle/a.jshj,4) end) 毛利率,sum(a.khs) 客户数,sum(a.hykds) 会员客单数,sum((case when nvl(a.khs,0)=0 then 0 else round(nvl(a.jshj,0)/a.khs,4) end)) 客单价,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) 线上销售额占比, a.hsmle 毛利额,a.hyxse 会员销售额,dx.dxje 积分抵现金额,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/i.xskl,2) 线上客单价,nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0) 线上价税合计, (case when nvl(a.jshj,0)=0 then 0 else 100*round(nvl(a.hyxse,0)/a.jshj,4) end) 会员销售占比,b.hyqb 会员钱包销售额,xs.fkje 惜食小程序,d.fkje 饿了么,c.fkje 美团外卖,f.fkje 美团点评,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) 线下销售额占比, h.fkje 收钱吧,g.fkje 抖音团购,i.xskl 线上客单数,j.xxkl 线下客单数 from ( select a.kdrq kdrq,b.mc mc,a.subbh subbh,ROUND(sum(a.jshj),2) jshj,sum(c.sj1) sj1, count(distinct a.lsh) as khs,count(distinct case when nvl(a.YHKH,' ')<>' ' then a.lsh else ' ' end) hykds, sum(case when nvl(a.yhkh,' ')<>' ' then a.jshj else 0 end) hyxse, sum(a.ml) hsmle,sum(a.ml) ml from subfhd a right join (select * from gl_custom where nvl(c_storetype,0)=1) b on a.subbh=b.tjbh right join (select * from yw_kck ) c on a.hh=c.hh where a.Kdrq = TRUNC(SYSDATE-1) and nvl(a.bz,' ')<>'会员礼品成本调整单' and nvl(a.bz,' ')<>'¥' group by a.subbh,a.kdrq,b.mc ) a left join (select kdrq,subbh,sum(jshj) dxje from subfhd where kdrq = TRUNC(SYSDATE-1) and hh='JFDX' group by subbh, kdrq ) dx on (a.subbh=dx.subbh and a.kdrq=dx.kdrq) left join ( select a.KDRQ,a.subbh,sum(a.fkje) hyqb from subdfkfs a inner join (select tjbh from gl_custom where nvl(c_storetype,0)=1) b on a.subbh=b.tjbh where a.fkfsid='hyqb' and KDRQ = TRUNC(SYSDATE-1) group by a.subbh,a.KDRQ ) b on (a.subbh=b.subbh and a.kdrq=b.kdrq) left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('SY-MTWM') group by SUBBH, KDRQ) c on a.subbh=c.subbh and a.kdrq=c.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('SYELM') group by SUBBH, KDRQ) d on a.subbh=d.subbh and a.kdrq=d.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('197') group by SUBBH, KDRQ) f on a.subbh=f.subbh and a.kdrq=f.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('801') group by SUBBH, KDRQ) g on a.subbh=g.subbh and a.kdrq=g.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('806') group by SUBBH, KDRQ) h on a.subbh=h.subbh and a.kdrq=h.kdrq left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('215') group by SUBBH, KDRQ) xs on a.subbh=xs.subbh and a.kdrq=xs.kdrq left join (select SUBBH, KDRQ,count(distinct xhlsh) xskl from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('SY-MTWM','SYELM','197','801','808','215') group by SUBBH, KDRQ) i on a.subbh=i.subbh and a.kdrq=i.kdrq left join (select SUBBH, KDRQ,count(distinct xhlsh) xxkl from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid not in ('SY-MTWM','SYELM','197','801','808','215') group by SUBBH, KDRQ) j on a.subbh=j.subbh and a.kdrq=j.kdrq group by a.subbh, a.mc, a.kdrq, a.jshj, a.hsmle,a.ml,b.hyqb,a.hyxse, (case when nvl(a.jshj,0)=0 then 0 else round(a.hsmle/a.jshj,4) end), dx.dxje, nvl(a.jshj-dx.dxje,a.jshj), (case when nvl(a.jshj,0)=0 then 0 else 100*round(nvl(a.hyxse,0)/a.jshj,4) end),c.fkje,d.fkje,f.fkje,g.fkje,h.fkje,xs.fkje,nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0) ,nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0) ,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) ,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) ,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/i.xskl,2) ,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/j.xxkl,2),i.xskl,j.xxkl order by a.subbh """ return sql def update_excel_sheet(excel_path, sheet_name, data, columns): """更新Excel指定sheet的数据 - 清空整个sheet后放入数据(包括标题行)""" try: # 加载工作簿 wb = load_workbook(excel_path) # 选择指定sheet if sheet_name in wb.sheetnames: ws = wb[sheet_name] else: ws = wb.create_sheet(sheet_name) # 清空整个工作表的所有数据 ws.delete_rows(1, ws.max_row) # 创建DataFrame(包含标题行) df = pd.DataFrame(data, columns=columns) # 将数据写入sheet(包括标题行) for r_idx, row in enumerate(dataframe_to_rows(df, index=False, header=True), 1): for c_idx, value in enumerate(row, 1): ws.cell(row=r_idx, column=c_idx, value=value) # 保存工作簿 wb.save(excel_path) print(f"成功更新 {sheet_name} 工作表,共 {len(data)} 行数据") return True except Exception as e: print(f"更新Excel失败: {str(e)}") return False def update_excel_data(excel_path): """更新Excel文件中的所有G3销售数据""" try: print("开始更新Excel数据...") # 更新月度G3阶段数据 print("正在查询月度G3阶段数据...") sql1 = generate_g3_monthly_sql() data1, columns1 = oracle_connect(sql1) if data1: print(f"查询到月度G3阶段数据 {len(data1)} 行") update_excel_sheet(excel_path, "月度G3阶段", data1, columns1) else: print("未查询到月度G3阶段数据") # 更新月度G3周度销售数据 print("正在查询月度G3周度销售数据...") sql2 = generate_g3_weekly_sql() data2, columns2 = oracle_connect(sql2) if data2: print(f"查询到月度G3周度销售数据 {len(data2)} 行") update_excel_sheet(excel_path, "月度G3周度销售", data2, columns2) else: print("未查询到月度G3周度销售数据") # 更新月度G3每日销售数据 print("正在查询月度G3每日销售数据...") sql3 = generate_g3_daily_monthly_sql() data3, columns3 = oracle_connect(sql3) if data3: print(f"查询到月度G3每日销售数据 {len(data3)} 行") update_excel_sheet(excel_path, "月度G3每日销售", data3, columns3) else: print("未查询到月度G3每日销售数据") # 更新昨日G3每日销售数据 print("正在查询昨日G3每日销售数据...") sql4 = generate_g3_daily_yesterday_sql() data4, columns4 = oracle_connect(sql4) if data4: print(f"查询到昨日G3每日销售数据 {len(data4)} 行") update_excel_sheet(excel_path, "昨日G3每日销售", data4, columns4) else: print("未查询到昨日G3每日销售数据") print("Excel数据更新完成") return True except Exception as e: print(f"更新Excel数据失败: {str(e)}") return False class ExcelScreenshot: """Excel截图类,处理COM初始化问题""" def __init__(self): self.excel_app = None self.workbook = None def initialize_com(self): """初始化COM对象""" try: pythoncom.CoInitialize() self.excel_app = win32.gencache.EnsureDispatch('Excel.Application') self.excel_app.Visible = True self.excel_app.DisplayAlerts = False return True except Exception as e: print(f"COM初始化失败: {str(e)}") return False def open_workbook(self, excel_path): """打开工作簿""" try: if not self.excel_app: if not self.initialize_com(): return False self.workbook = self.excel_app.Workbooks.Open(excel_path) return True except Exception as e: print(f"打开工作簿失败: {str(e)}") return False def capture_sheet(self, sheet_name, screenshot_path): """截图指定工作表""" try: if not self.workbook: return False # 选择工作表 worksheet = self.workbook.Sheets(sheet_name) self.workbook.Windows(1).Activate() worksheet.Activate() # 获取有数据的区域 used_range = worksheet.UsedRange if used_range is None: print(f"{sheet_name} 工作表没有数据") return False used_range.Select() # 等待Excel刷新 time.sleep(2) # 复制选中的区域 worksheet.Range(used_range.Address).CopyPicture(Appearance=1, Format=2) # 从剪贴板获取图片并保存 time.sleep(1) image = ImageGrab.grabclipboard() if image: image.save(screenshot_path) return True else: return False except Exception as e: print(f"截图 {sheet_name} 失败: {str(e)}") return False def close(self): """关闭Excel应用""" try: if self.workbook: self.workbook.Close(SaveChanges=False) if self.excel_app: self.excel_app.Quit() pythoncom.CoUninitialize() except Exception as e: print(f"关闭Excel失败: {str(e)}") def capture_excel_screenshots(excel_path): """截图Excel的四个sheet表有数据的区域""" screenshot = ExcelScreenshot() screenshot_paths = [] try: print("开始截图Excel工作表...") # 初始化并打开工作簿 if not screenshot.open_workbook(excel_path): raise Exception("无法打开Excel文件") sheet_names = ["销售", "品类", "主推品", "昨日销售"] for sheet_name in sheet_names: try: print(f"正在截图 {sheet_name} 工作表...") screenshot_path = f"D:\\仲景生活\\{sheet_name}_截图_{dt.datetime.now().strftime('%Y%m%d%H%M%S')}.png" if screenshot.capture_sheet(sheet_name, screenshot_path): screenshot_paths.append(screenshot_path) print(f"成功截图 {sheet_name} 工作表,保存为: {screenshot_path}") else: print(f"截图失败 {sheet_name} 工作表") except Exception as e: print(f"截图 {sheet_name} 失败: {str(e)}") continue print(f"截图完成,共生成 {len(screenshot_paths)} 张截图") return screenshot_paths except Exception as e: print(f"截图Excel失败: {str(e)}") return [] finally: screenshot.close() def application_push_image(access_token, image_path, user_id="037565", agent_id="1000077"): """推送图片到企业微信应用""" try: # 上传图片获取media_id with open(image_path, 'rb') as f: files = {'media': f} upload_url = f'https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={access_token}&type=image' upload_response = requests.post(upload_url, files=files).json() if 'media_id' not in upload_response: print(f"图片上传失败: {upload_response}") return None media_id = upload_response['media_id'] # 发送图片消息 send_url = f'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}' payload = { "touser": user_id, "msgtype": "image", "agentid": agent_id, "image": {"media_id": media_id}, "safe": 0 } response = requests.post(send_url, json=payload).json() return response except Exception as e: print(f"图片发送失败: {str(e)}") return None def webhook_push_image(image_path, webhook_url): """通过webhook推送图片到企业微信群""" try: # 读取图片并转换为base64 with open(image_path, 'rb') as f: image_data = f.read() # 上传到临时位置或直接使用base64 image_base64 = base64.b64encode(image_data).decode('utf-8') # 构建消息内容 payload = { "msgtype": "image", "image": { "base64": image_base64, "md5": hashlib.md5(image_data).hexdigest() } } response = requests.post(webhook_url, json=payload) return response.json() except Exception as e: print(f"Webhook图片发送失败: {str(e)}") return None def send_excel_report(): """发送Excel报表截图""" try: print(f"{dt.datetime.now()} - 开始执行Excel报表推送任务") # 初始化微信 wechat = Wechat('tXNMrgcTgeV3IAqJhWB7mOe_bcKe9EtdCDze_75mGeY') access_token = wechat.access_token() # 群webhook地址 webhook_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=3cb06b7e-3658-4fbd-9676-54fc25fea470" excel_path = r"D:\仲景生活\月度销售汇总.xlsx" # 检查文件是否存在 if not os.path.exists(excel_path): print(f"Excel文件不存在: {excel_path}") # 创建空的Excel文件 wb = load_workbook() wb.save(excel_path) print("已创建新的Excel文件") # 更新Excel数据 if not update_excel_data(excel_path): raise Exception("Excel数据更新失败") # 截图四个sheet表 screenshot_paths = capture_excel_screenshots(excel_path) if not screenshot_paths: print("Excel截图失败,尝试使用备用截图方法...") # 备用方案:使用pyautogui截图 screenshot_paths = capture_with_pyautogui(excel_path) if not screenshot_paths: raise Exception("所有截图方法都失败了") # 推送所有截图到个人 success_count_personal = 0 for image_path in screenshot_paths: if os.path.exists(image_path): print(f"正在推送图片到个人: {os.path.basename(image_path)}") result = application_push_image(access_token, image_path, "037565") if result and result.get('errcode') == 0: success_count_personal += 1 print(f"成功发送到个人: {os.path.basename(image_path)}") else: print(f"发送到个人失败: {os.path.basename(image_path)} - {result}") # 推送所有截图到群 success_count_group = 0 for image_path in screenshot_paths: if os.path.exists(image_path): print(f"正在推送图片到群: {os.path.basename(image_path)}") result = webhook_push_image(image_path, webhook_url) if result and result.get('errcode') == 0: success_count_group += 1 print(f"成功发送到群: {os.path.basename(image_path)}") else: print(f"发送到群失败: {os.path.basename(image_path)} - {result}") # 删除已发送的截图 for image_path in screenshot_paths: if os.path.exists(image_path): os.remove(image_path) print(f"已删除截图文件: {os.path.basename(image_path)}") print(f"{dt.datetime.now()} - Excel报表推送完成") print(f"个人成功发送: {success_count_personal}/{len(screenshot_paths)}") print(f"群成功发送: {success_count_group}/{len(screenshot_paths)}") return success_count_personal > 0 or success_count_group > 0 except Exception as e: print(f"{dt.datetime.now()} - Excel报表推送失败: {str(e)}") import traceback traceback.print_exc() return False def capture_with_pyautogui(excel_path): """备用截图方法:使用pyautogui""" try: import pyautogui import subprocess import time # 使用Excel打开文件 subprocess.Popen([excel_path], shell=True) time.sleep(5) screenshot_paths = [] sheet_names = ["销售", "品类", "主推品", "昨日销售"] for sheet_name in sheet_names: try: # 这里需要根据实际情况调整截图区域 screenshot_path = f"D:\\仲景生活\\{sheet_name}_截图_{dt.datetime.now().strftime('%Y%m%d%H%M%S')}.png" # 全屏截图(需要手动调整) screenshot = pyautogui.screenshot() screenshot.save(screenshot_path) screenshot_paths.append(screenshot_path) print(f"使用pyautogui截图: {screenshot_path}") except Exception as e: print(f"pyautogui截图失败: {str(e)}") continue return screenshot_paths except Exception as e: print(f"备用截图方法失败: {str(e)}") return [] def run_scheduler(): """运行定时任务""" # 每天早上8:30执行 schedule.every().day.at("08:30").do(send_excel_report) # 立即测试一次 print(f"{dt.datetime.now()} - 正在执行首次测试...") send_excel_report() while True: schedule.run_pending() time.sleep(60) if __name__ == '__main__': print(f'程序启动时间: {dt.datetime.now()}') # 确保目录存在 output_dir = r'D:\仲景生活' if not os.path.exists(output_dir): os.makedirs(output_dir) print(f"已创建目录: {output_dir}") # 启动定时任务线程 scheduler_thread = Thread(target=run_scheduler) scheduler_thread.daemon = True scheduler_thread.start() try: while True: time.sleep(60) except KeyboardInterrupt: print("程序已停止") 推送的截图中销售的图右侧有过多无数据区域,品类下侧有部分无数据区域,昨日销售右侧有部分无数据区域,修正代码,自动精确截图区域 只写出需要修改部分代码
09-25
<think>好的,我现在需要解决用户的问题,即修正推送的截图中存在过多无数据区域的问题。用户提到销售图右侧、品类下侧和昨日销售右侧都有多余的空白区域,需要自动精确截图区域。我需要仔细分析现有的代码,找到问题所在,并进行修改。 首先,我回顾一下用户提供的代码。截图功能是在ExcelScreenshot类中实现的,特别是capture_sheet方法。该方法通过COM操作Excel,选择工作表的已用区域,然后复制图片保存。问题可能出在如何确定需要截图的区域上。 当前的capture_sheet方法使用worksheet.UsedRange来获取有数据的区域,但看起来可能不够精确,导致包含了多余的空白行或列。例如,UsedRange可能会包含一些隐藏的行或列,或者在某些情况下没有正确更新,导致截图区域过大。 我需要找到一种方法,精确地确定数据区域的实际范围,排除无数据的空白部分。通常,Excel中的UsedRange可能会包括所有曾经被格式化或有内容的单元格,即使它们现在为空。因此,可能需要更精确地计算实际的数据行和列。 可能的解决方案包括: 1. 找到数据区域的最后一行和最后一列,然后定义一个精确的范围。 2. 使用SpecialCells方法定位最后包含数据的单元格。 3. 遍历行和列,找到最后一个非空单元格的位置。 在VBA中,常用的方法是使用End(xlUp)或End(xlToLeft)来找到数据边缘,但在Python中通过COM调用可能需要类似的方法。例如,可以通过获取工作表中最后一行和最后一列的索引,然后定义一个范围。 查看当前的代码,capture_sheet方法中的used_range = worksheet.UsedRange,可能需要替换为更精确的范围选择。例如,找到最后一行和最后一列,然后创建一个从A1到该行列的范围。 例如,可以使用以下步骤: - 获取最后一行:worksheet.Cells.SpecialCells(xlCellTypeLastCell).Row - 获取最后一列:worksheet.Cells.SpecialCells(xlCellTypeLastCell).Column - 然后定义范围为A1到该行列的单元格。 不过,xlCellTypeLastCell可能在COM中对应的常量需要正确引用。或者,可以使用另一种方法,比如从第一行第一列开始,找到最右和最下的非空单元格。 或者,可以使用UsedRange的Rows和Columns的Count属性来调整范围,但可能需要更精确的控制。 另外,在用户提供的代码中,used_range.Select()之后,可能选中了整个UsedRange,包括多余的区域。因此,需要修改这部分代码,选择一个更精确的范围。 可能的修改步骤: 在ExcelScreenshot类的capture_sheet方法中,将used_range替换为更精确的范围定义。例如: worksheet.Cells.SpecialCells(11) # 11对应xlCellTypeLastCell 但需要确保正确引用常量。或者,使用以下方法: last_row = worksheet.Cells.Find("*", SearchOrder=win32.constants.SearchOrder.xlByRows, SearchDirection=win32.constants.SearchDirection.xlPrevious).Row last_col = worksheet.Cells.Find("*", SearchOrder=win32.constants.SearchOrder.xlByColumns, SearchDirection=win32.constants.SearchDirection.xlPrevious).Column 这样可以找到最后一个包含数据的单元格的位置,然后定义范围为A1到该行列。 接下来,在capture_sheet方法中,修改选择区域的代码: used_range = worksheet.Range(worksheet.Cells(1, 1), worksheet.Cells(last_row, last_col)) 这样,选中的区域就是实际数据所在的区域,避免多余的空白。 因此,需要修改capture_sheet方法中的used_range部分。具体来说,替换: used_range = worksheet.UsedRange 为: # 找到最后一个有数据的行和列 last_cell = worksheet.Cells.Find("*", SearchOrder=2, SearchDirection=2) # 2对应xlByRows和xlPrevious if last_cell: last_row = last_cell.Row last_col = last_cell.Column used_range = worksheet.Range(worksheet.Cells(1, 1), worksheet.Cells(last_row, last_col)) else: # 默认使用UsedRange,如果找不到数据 used_range = worksheet.UsedRange 这里需要注意,win32.constants中的常量可能需要正确引用。例如,SearchOrder=win32.constants.xlByRows,SearchDirection=win32.constants.xlPrevious。但用户代码中可能没有导入这些常量,可能需要使用数值代替,如1表示xlByRows,2表示xlByColumns;1表示xlNext,2表示xlPrevious。 或者,可以尝试使用以下代码: last_row = worksheet.Cells.Find("*", SearchOrder=2, SearchDirection=2).Row last_col = worksheet.Cells.Find("*", SearchOrder=1, SearchDirection=2).Column 但需要处理可能找不到的情况,否则会导致异常。 因此,在capture_sheet方法中,需要调整used_range的定义,使其精确到实际数据区域。 此外,用户提到的备用截图方法capture_with_pyautogui可能也需要调整,但用户的问题主要集中在Excel的截图部分,因此可能不需要修改备用方法。 总结需要修改的部分: 在ExcelScreenshot类的capture_sheet方法中,替换used_range的定义,使用更精确的方法确定数据区域的范围。 另外,可能需要调整Excel的视图模式,例如切换到页面布局视图,或者调整列宽自动适应,以确保截图时数据区域正确显示。 现在,根据用户的要求,只写出需要修改的部分代码,即ExcelScreenshot类的capture_sheet方法中的相关部分。 </think>需要修改ExcelScreenshot类的capture_sheet方法,精确选择有数据的区域: ```python def capture_sheet(self, sheet_name, screenshot_path): """截图指定工作表的精确数据区域""" try: if not self.workbook: return False worksheet = self.workbook.Sheets(sheet_name) self.workbook.Windows(1).Activate() worksheet.Activate() # 获取实际数据范围 # 找到最后一个有数据的单元格 last_cell = worksheet.Cells.Find("*", SearchOrder=2, SearchDirection=2) # 2对应xlByColumns和xlPrevious if last_cell: last_row = last_cell.Row last_col = last_cell.Column # 定义精确范围(从A1到实际最后一行最后一列) used_range = worksheet.Range(worksheet.Cells(1, 1), worksheet.Cells(last_row, last_col)) else: used_range = worksheet.UsedRange # 扩展选择范围(可选:增加5%的缓冲区域) buffer_row = max(1, int(used_range.Rows.Count * 0.05)) buffer_col = max(1, int(used_range.Columns.Count * 0.05)) expanded_range = worksheet.Range( used_range.Cells(1, 1), worksheet.Cells(used_range.Rows.Count + buffer_row, used_range.Columns.Count + buffer_col) ) # 选择精确范围 expanded_range.Select() # 等待Excel刷新 time.sleep(1) # 复制选中的区域 worksheet.Range(used_range.Address).CopyPicture(Appearance=1, Format=2) # 从剪贴板获取图片并保存 time.sleep(0.5) image = ImageGrab.grabclipboard() if image: image.save(screenshot_path) return True else: return False except Exception as e: print(f"截图 {sheet_name} 失败: {str(e)}") return False ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值