b/s数据统计_S3记录到统计报告

本文探讨了亚马逊AWS的S3存储服务,其作为高效云存储解决方案的角色,以及如何利用Sisense、S3Stat和CloudBuddy Analytics等工具进行日志分析,以获取关于存储桶使用情况的有效报告。

b/s数据统计

云是技术中的新流行语。 尽管云在许多设计图或架构图中主要表示互联网,但云计算已缓慢但肯定地演变为三种定义明确的服务,即IaaS,PaaS和SaaS。

当我们谈论IaaS时; 该服务空间的领先者是亚马逊,其服务缩写为AWS(Amazon Web Services)。 提供的服务之一,被广泛接受,称为简单存储服务(S3)。

扩展表明,S3是AWS的存储翼。 截止到2009年2月,S3已存储了400亿个对象,无论如何都不小。 AWS本身在其社区中拥有49万名开发人员。 因此,计算平均份额,每个开发人员大约有82000。 所有这一切对于亚马逊来说意味着更多的钱,而对于用户来说则更少。 但是,采用按需付费的模型,您将不会真正感受到压力。

对于需要在云中存储多个字节的人来说,S3是一种非常有效的存储机制。 您所需要做的就是一个AWS账户,并准备通过创建名为S3的唯一对象来开始使用

水桶 。 值区名称通常表示内容的性质。 例如,如果您的公司名为“ Open Ink”,而您想将库存数据的Giga / Tera字节存储在S3上,则可以创建存储区“ openink-inventory”,然后将所有数据移到那里。 AWS为您使用的带宽和存储收费。

由于您可能不是公司中唯一访问此数据的人。 每次访问都意味着一滴干透了。 您可能需要一种机制,以某种方式跟踪正在发生的事情,正在访问的人,从何处访问它等。

可悲的是,您可以跟踪的唯一方法是启用存储桶日志记录,然后至少可以说通读那些神秘的日志。 但是,尽管如此,它们仍然是有效的日志,并且它们被证明是可用于提供有效报告的少数工具的有用数据。 我将看三种工具,

SisenseS3StatCloudBuddy Analytics ,并查看它们之间的比较。

                Sisense      S3Stat       CloudBuddy Analytics
Basic 
Size               11M          -             9M
Platform           Windows      -             Windows
MultiAccount       Yes          No            Yes  
MultiUser          No           No            Yes
Engine             Prism        Webalizer     AWStats
Install            Local        -             Local(Web Based)
Cost               Trial        $5/month      Free(Open Source) 
Reports 
Month-wise        Yes            Yes          Yes
Weekly            Yes            Yes          Yes
Hourly            Yes            Yes          Yes
Bandwidth         Yes            Yes          Yes
OS type           Yes            Yes          Yes
File type         Yes            Yes          Yes
IP Geography      Yes            Yes          Yes
Top Files         Yes            Yes          Yes
Visits            Yes            Yes          Yes
Browsers          Yes            Yes          Yes
Customizable      Yes            No           Yes*
Extensible        No             No           Yes 
Others 
UI                Good           Basic        Basic
Usage Ease        Cumbersome     Easy         Easy 
* - You need to drill the code.  
看一下功能集,他们都出售包装不同的同一个东西。 因此,很难就它们提供的功能得出任何结论。 但是在尺寸,成本核算,UI和可扩展性等其他方面,您可以选择很多差异。

参考文献:

http://www.datacenterknowledge.com/a...llion-objects/ http://aws.amazon.com/s3/ http://www.mycloudbuddy.com/ http://www.s3stat.com/ http://www.sisense.com/AmazonS3.aspx

翻译自: https://bytes.com/topic/networking/insights/872450-s3-logs-statistical-reports

b/s数据统计

Excel报表上报&统计系统能够将电子表格软件MS Excel和大型数据库管理系统MS SQL Server 2000/2005/2008集成为一个网络报表平台。在这个平台上,用户可以充分利用MS Excel软件,通过本系统,实现Excel报表的收集及统计,轻松 、快速构建能够适应变化的网络报表系统,是一个非常实用的报表收集及统计工具。 Excel报表上报&统计系统,也可以在互联网上使用。 1.1 系统特色 1.灵活的模板管理功,通过报表模板定义,用户可以定义上报报表样式、填报单元格、统计单元格,可适应报表灵活的变化。 2.可控制报表的查询、填写权限,由用户根据权限设计、管理模板,大大增强了系统的适应性和可用性 3.可以使用户通过互联网或局域网进行填报 、修改、查询数据和引用外部数据源。 5.具有组织机构字典,可以分部门层次管理报表。 6.支持报表导入、导出功能。 7.只要会用Excel,就很容易使用本系统,培训成本和维护成本大大降低。 8.支持报表表间统计功能。 9.采用MS SQL Server2000作为系统数据库,企业的Excel文件和业务数据具有安全保障。 10.软件采用B/S结构,适用于局域网和广域网。只在一服务器端安装,其它用户只要用IE就可使用本系统,安装维护方便。 11.支持模板导入和模板导出功能。 12.灵活的用户权限管理。 13.可定制按条件删除数据任务。 14.支持Excel2000、Excel 2003、Excel 2007。 [返回页首] 1.2 系统主要功能 1、报表分部门上报收集功能。 2、报表查询功能。 3、报表多表合并统计功能。 4、报表模板自定义功能。 5、用户权限管理功能。 6、部门管理功能。 7、报表从Excel导出、打印功能。 [返回页首] 1.3 系统应用对象 政府机关、邮电通信、计算机、网络、商业/贸易、银行/金融/证券/保险/投资、税务、咨询、社会服务、旅游/饭店、健康/医疗服务、房地产、交通运输、法律/司法、娱乐/体育、媒介/广告、科研/教育、农业/渔业/林业/畜牧业、矿业/制造业等行业的报表管理用户。 2.软件注册 未注册的软件是试用版,试用版功能未有限制,但只能上报可达5张报表,使用次数可达15次。 如果您需要购买正式版,请遵循以下的购买流程。 第一步、用户与南昌鸣谦科技公司联系,商定合同。 联系方式: 电话:18970088701 电子邮件:mqcell@163.com 第二步、用户汇款 收款单位:南昌市鸣谦科技有限公司 开户银行:中国银行南昌市省府大院支行 帐号 :726466844258091001 第三步、用户把注册程序的机器码,通过电子邮件发送到鸣谦科技 或电话通知鸣谦科技公司。 第四步、鸣谦科技公司收到机器码和汇款后,将注册码通过电子邮件发送给用户或短信、电话通知对方。 第五步、用户输入注册码,软件变成正式版。
import pyodbc import pandas as pd from sqlalchemy import create_engine, text, VARCHAR from urllib.parse import quote_plus import uuid import numpy as np from tqdm import tqdm import time import re import traceback def get_table_columns(engine, table_name): “”“获取表的实际列名”“” with engine.connect() as conn: result = conn.execute(text(f"SHOW COLUMNS FROM {table_name}")) columns = [row[0] for row in result] return columns def safe_get_column_name(columns, possible_names): “”“安全获取列名(处理大小写和前缀)”“” lower_columns = [col.lower() for col in columns] for name in possible_names: # 尝试精确匹配 if name in columns: return name # 尝试小写匹配 if name.lower() in lower_columns: return columns[lower_columns.index(name.lower())] # 尝试模糊匹配 for col in columns: if any(name in col for name in possible_names): return col return None def compare_records(row, existing_row, fields_to_compare): “”“比较两个记录,返回需要更新的字段和一致字段数量”“” changes = {} consistent_fields = 0 total_fields = 0 for field in fields_to_compare: total_fields += 1 # 处理可能的NaN值 new_val = row[field] if pd.notna(row[field]) else None old_val = existing_row[field] if field in existing_row and pd.notna(existing_row[field]) else None # 比较值是否不同 if new_val != old_val: changes[field] = new_val else: consistent_fields += 1 return changes, consistent_fields, total_fields def generate_unique_guids(count): “”“生成唯一的小写GUID列表并确保唯一性”“” guids = set() while len(guids) < count: guids.add(str(uuid.uuid4()).lower()) return list(guids) def main(): print(“=” * 80) print(“数据同步程序启动”) print(f"开始时间: {time.strftime(‘%Y-%m-%d %H:%M:%S’)}“) print(”=" * 80) # 1. 安全处理包含特殊字符的密码 password = "@Aa.1234" encoded_password = quote_plus(password) # 对特殊字符进行URL编码 # 2. 创建MySQL连接字符串 mysql_conn_str = ( f"mysql+pymysql://lpsoft:{encoded_password}@192.168.3.1:3306/OrderManage" "?charset=utf8mb4" ) # 3. 创建SQLAlchemy引擎 mysql_engine = create_engine( mysql_conn_str, pool_size=5, max_overflow=10, pool_timeout=30, connect_args={&#39;connect_timeout&#39;: 15} ) # 4. 测试MySQL连接 try: with mysql_engine.connect() as test_conn: test_conn.execute(text("SELECT 1")) print("✅ MySQL连接测试成功") except Exception as e: print(f"❌ MySQL连接失败: {str(e)}") return # 5. 获取MySQL表结构 print("正在获取MySQL表结构...") try: table_columns = get_table_columns(mysql_engine, "T_Customer") print(f"表字段: {&#39;, &#39;.join(table_columns)}") # 安全获取电话字段名 phone_field = safe_get_column_name(table_columns, ["phone", "Phone", "telephone", "tel"]) if not phone_field: raise ValueError("找不到电话字段") print(f"✅ 确定电话字段: {phone_field}") except Exception as e: print(f"❌ 表结构获取失败: {str(e)}") return # 6. 连接SQL Server (SAP数据) try: sap_conn = pyodbc.connect( &#39;DRIVER={ODBC Driver 17 for SQL Server};&#39; &#39;SERVER=192.168.0.229;&#39; &#39;DATABASE=SINO_SAP;&#39; &#39;UID=SAPReader;&#39; &#39;PWD=Sino2025zyq;&#39; ) print("✅ SQL Server连接成功") except Exception as e: print(f"❌ SQL Server连接失败: {str(e)}") return # 7. 从SQL Server获取SAP数据(使用新的查询) sap_query = """ SELECT CAST(111100000048210 + ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS bigint) AS Id, CAST(LOWER(NEWID()) AS varchar(50)) AS GUID, CAST(&#39;ipcc.org&#39; AS varchar(50)) AS Domain, CAST( CASE WHEN ZY_TB_CustomerProfile.[客户类型] = &#39;VIP&#39; THEN &#39;703192237850693&#39; ELSE &#39;703192237846597&#39; END AS varchar(20)) AS CustomerTypeCode, CAST(&#39;&#39; AS text) AS Remark, CAST(ZY_TB_CustomerPhone.CardCode AS varchar(50)) AS S6, CAST(ZY_TB_CustomerPhone.Cardname AS varchar(100)) AS CompanyName, CAST(ZY_TB_CustomerPhone.Name AS varchar(50)) AS Name, CAST(LEFT(ZY_TB_CustomerPhone.Telephone, 15) AS varchar(15)) AS Phone, CAST(FORMAT(ZY_TB_CustomerProfile.近一年总毛利, &#39;N2&#39;) AS varchar(50)) AS S4, CAST(FORMAT(ZY_TB_CustomerProfile.预收款金额, &#39;N2&#39;) AS varchar(50)) AS S2, CAST(FORMAT(ZY_TB_CustomerProfile.应收款, &#39;N2&#39;) AS varchar(50)) AS S1, CAST(FORMAT(ZY_TB_CustomerProfile.全部库存金额, &#39;N2&#39;) AS varchar(50)) AS S3, CAST((CAST(ZY_TB_CustomerProfile.客户等级 AS varchar(50)) + ZY_TB_CustomerProfile.等级名称) AS varchar(50)) AS S5 FROM ZY_TB_CustomerPhone LEFT JOIN ZY_TB_CustomerProfile ON ZY_TB_CustomerPhone.CardCode = ZY_TB_CustomerProfile.[客户编号] WHERE ZY_TB_CustomerPhone.CardCode IS NOT NULL AND ZY_TB_CustomerPhone.Cardname IS NOT NULL AND ZY_TB_CustomerPhone.Telephone NOT LIKE &#39;8441%&#39; AND ZY_TB_CustomerPhone.Cardname NOT LIKE &#39;%中源合聚生物%&#39; AND ZY_TB_CustomerPhone.CardCode <> &#39;&#39; AND ZY_TB_CustomerPhone.Cardname <> &#39;&#39; """ print("正在从SAP数据库加载数据...") start_time = time.time() try: df_sap = pd.read_sql(sap_query, sap_conn) # 确保电话字段格式正确 df_sap[&#39;Phone&#39;] = df_sap[&#39;Phone&#39;].astype(str).str.slice(0, 15) sap_duration = time.time() - start_time print(f"✅ 从SAP加载了 {len(df_sap)} 条记录 (耗时: {sap_duration:.2f}秒)") except Exception as e: print(f"❌ SAP数据加载失败: {str(e)}") return # 8. 从MySQL获取现有客户数据(使用动态字段名) print("正在从MySQL加载现有客户数据...") start_time = time.time() try: # 动态生成查询 query = f"SELECT * FROM T_Customer" df_existing = pd.read_sql(query, mysql_engine) # 确保电话字段存在 if phone_field not in df_existing.columns: raise ValueError(f"电话字段 &#39;{phone_field}&#39; 在查询结果中不存在") # 处理电话字段 df_existing[&#39;Phone&#39;] = df_existing[phone_field].astype(str).str.slice(0, 15) # 创建以Phone为键的字典,便于快速查找 existing_dict = df_existing.set_index(&#39;Phone&#39;).to_dict(&#39;index&#39;) mysql_duration = time.time() - start_time print(f"✅ MySQL现有 {len(df_existing)} 条记录 (耗时: {mysql_duration:.2f}秒)") except Exception as e: print(f"❌ MySQL数据加载失败: {str(e)}") print("请检查表结构和字段名") return # 9. 定义需要比较和更新的字段(已添加CompanyName) fields_to_update = [ &#39;S6&#39;, &#39;CustomerTypeCode&#39;, &#39;S5&#39;, &#39;S1&#39;, &#39;S2&#39;, &#39;S3&#39;, &#39;S4&#39;, &#39;CompanyName&#39; # 新增字段 ] # 10. 数据对比分析 print("\n" + "=" * 80) print("开始数据对比分析...") print(f"比较字段: {&#39;, &#39;.join(fields_to_update)}") # 初始化统计变量 stats = { &#39;total_records&#39;: len(df_sap), &#39;existing_records&#39;: 0, &#39;new_records&#39;: 0, &#39;consistent_records&#39;: 0, &#39;inconsistent_records&#39;: 0, &#39;total_fields_compared&#39;: 0, &#39;consistent_fields&#39;: 0, &#39;inconsistent_fields&#39;: 0, &#39;max_consistent_fields&#39;: 0, &#39;min_consistent_fields&#39;: len(fields_to_update), # 初始设为最大字段数 &#39;update_candidates&#39;: 0 } # 存储需要更新和插入的记录 updates_to_apply = [] # 存储需要更新的记录和变化字段 inserts_to_apply = [] # 存储需要插入的新记录(仅业务字段) # 进度条显示 pbar = tqdm(total=len(df_sap), desc="分析记录") # 11. 遍历所有SAP记录 for idx, row in df_sap.iterrows(): phone = row[&#39;Phone&#39;] # 检查电话是否存在于现有数据中 if phone in existing_dict and phone: # 确保phone不为空 stats[&#39;existing_records&#39;] += 1 existing_row = existing_dict[phone] # 比较记录并获取变化 - 只比较需要更新的字段 changes, consistent_fields, total_fields = compare_records(row, existing_row, fields_to_update) stats[&#39;total_fields_compared&#39;] += total_fields stats[&#39;consistent_fields&#39;] += consistent_fields stats[&#39;inconsistent_fields&#39;] += (total_fields - consistent_fields) # 更新最大/最小一致字段数 stats[&#39;max_consistent_fields&#39;] = max(stats[&#39;max_consistent_fields&#39;], consistent_fields) stats[&#39;min_consistent_fields&#39;] = min(stats[&#39;min_consistent_fields&#39;], consistent_fields) # 检查是否完全一致 if len(changes) == 0: stats[&#39;consistent_records&#39;] += 1 else: stats[&#39;inconsistent_records&#39;] += 1 stats[&#39;update_candidates&#39;] += 1 changes[&#39;Phone&#39;] = phone # 添加标识符 updates_to_apply.append(changes) else: # 新记录 - 只保存业务字段 stats[&#39;new_records&#39;] += 1 new_record = { &#39;CustomerTypeCode&#39;: row[&#39;CustomerTypeCode&#39;], &#39;S6&#39;: row[&#39;S6&#39;], &#39;CompanyName&#39;: row[&#39;CompanyName&#39;], &#39;Name&#39;: row[&#39;Name&#39;], &#39;Phone&#39;: row[&#39;Phone&#39;], &#39;S4&#39;: row[&#39;S4&#39;], &#39;S2&#39;: row[&#39;S2&#39;], &#39;S1&#39;: row[&#39;S1&#39;], &#39;S3&#39;: row[&#39;S3&#39;], &#39;S5&#39;: row[&#39;S5&#39;] } inserts_to_apply.append(new_record) pbar.update(1) pbar.close() # 12. 打印详细统计信息 print("\n" + "=" * 80) print("数据对比统计结果:") print(f"总记录数: {stats[&#39;total_records&#39;]}") print(f"已存在记录数: {stats[&#39;existing_records&#39;]} ({stats[&#39;existing_records&#39;] / stats[&#39;total_records&#39;]:.1%})") print(f"新增记录数: {stats[&#39;new_records&#39;]} ({stats[&#39;new_records&#39;] / stats[&#39;total_records&#39;]:.1%})") print(f"一致记录数: {stats[&#39;consistent_records&#39;]} ({stats[&#39;consistent_records&#39;] / stats[&#39;existing_records&#39;]:.1%})") print( f"不一致记录数: {stats[&#39;inconsistent_records&#39;]} ({stats[&#39;inconsistent_records&#39;] / stats[&#39;existing_records&#39;]:.1%})") print(f"需要更新记录数: {stats[&#39;update_candidates&#39;]}") print(f"需要插入记录数: {stats[&#39;new_records&#39;]}") print(f"\n字段级别对比:") print(f"总比较字段数: {stats[&#39;total_fields_compared&#39;]}") print( f"一致字段数: {stats[&#39;consistent_fields&#39;]} ({stats[&#39;consistent_fields&#39;] / stats[&#39;total_fields_compared&#39;]:.1%})") print( f"不一致字段数: {stats[&#39;inconsistent_fields&#39;]} ({stats[&#39;inconsistent_fields&#39;] / stats[&#39;total_fields_compared&#39;]:.1%})") print(f"字段一致性范围: {stats[&#39;min_consistent_fields&#39;]}-{stats[&#39;max_consistent_fields&#39;]} (每记录一致字段数)") print("=" * 80 + "\n") # 13. 执行批量更新操作(包含CompanyName字段) if updates_to_apply: print(f"开始批量更新 {len(updates_to_apply)} 条有变化的记录...") start_time = time.time() try: # 创建包含变化的DataFrame df_changes = pd.DataFrame(updates_to_apply) # 打印更新示例 if not df_changes.empty: print(f"示例更新记录: 手机号={df_changes.iloc[0][&#39;Phone&#39;]}, 变化字段数={len(df_changes.columns) - 1}") # 创建临时表存储更新数据 temp_table_name = "temp_customer_updates" with mysql_engine.begin() as conn: # 先删除可能存在的旧临时表 conn.execute(text(f"DROP TABLE IF EXISTS {temp_table_name}")) # 定义列类型映射(包含CompanyName) dtype = { &#39;Phone&#39;: VARCHAR(15), # 指定固定长度 &#39;S6&#39;: VARCHAR(50), &#39;CustomerTypeCode&#39;: VARCHAR(20), &#39;S5&#39;: VARCHAR(50), &#39;S1&#39;: VARCHAR(50), &#39;S2&#39;: VARCHAR(50), &#39;S3&#39;: VARCHAR(50), &#39;S4&#39;: VARCHAR(50), &#39;CompanyName&#39;: VARCHAR(100) # 新增字段类型 } # 创建临时表(只包含变化的字段)并指定列类型 df_changes.to_sql( temp_table_name, mysql_engine, if_exists=&#39;replace&#39;, index=False, dtype=dtype ) # 添加前缀索引加速更新 with mysql_engine.begin() as conn: # 创建前缀索引 (Phone(15)) conn.execute(text(f"CREATE INDEX idx_phone ON {temp_table_name} (Phone(15))")) # 动态生成SET子句 - 只更新fields_to_update中的字段 set_clauses = [] for col in df_changes.columns: if col != &#39;Phone&#39;: # 跳过标识符字段 set_clauses.append(f"t.{col} = tmp.{col}") set_clause = ", ".join(set_clauses) # 使用JOIN执行批量更新 update_query = f""" UPDATE T_Customer AS t JOIN {temp_table_name} AS tmp ON LEFT(t.{phone_field}, 15) = tmp.Phone SET {set_clause} """ with mysql_engine.begin() as conn: result = conn.execute(text(update_query)) update_duration = time.time() - start_time print(f"✅ 成功更新 {result.rowcount} 条记录 (耗时: {update_duration:.2f}秒)") except Exception as e: print(f"❌ 更新操作失败: {str(e)}") # 记录错误详情 error_file = f"update_error_{time.strftime(&#39;%Y%m%d_%H%M%S&#39;)}.log" with open(error_file, &#39;w&#39;) as f: f.write(f"错误时间: {time.strftime(&#39;%Y-%m-%d %H:%M:%S&#39;)}\n") f.write(f"错误信息: {str(e)}\n") f.write("部分更新数据:\n") if &#39;df_changes&#39; in locals(): f.write(df_changes.head().to_string()) print(f"错误详情已保存到: {error_file}") traceback.print_exc() # 14. 执行批量插入操作(包含CompanyName字段) if inserts_to_apply: print(f"开始准备插入 {len(inserts_to_apply)} 条新记录...") start_time = time.time() try: # 准备插入数据 df_insert = pd.DataFrame(inserts_to_apply) # 获取当前最大ID max_id_query = "SELECT COALESCE(MAX(id), 111100000048210) AS max_id FROM T_Customer" with mysql_engine.connect() as conn: max_id = conn.execute(text(max_id_query)).scalar() # 生成新ID(从最大ID+1开始) new_ids = range(max_id + 1, max_id + 1 + len(df_insert)) # 生成唯一的小写GUID(确保在集合中唯一) new_guids = generate_unique_guids(len(df_insert)) # 添加呼叫中心系统生成的ID和GUID df_insert[&#39;id&#39;] = list(new_ids) df_insert[&#39;GUID&#39;] = new_guids df_insert[&#39;Domain&#39;] = &#39;ipcc.org&#39; df_insert[&#39;Remark&#39;] = &#39;&#39; # 选择并排序列以匹配表结构(包含CompanyName) insert_columns = [ &#39;id&#39;, &#39;GUID&#39;, &#39;Domain&#39;, &#39;CustomerTypeCode&#39;, &#39;Remark&#39;, &#39;S6&#39;, &#39;CompanyName&#39;, &#39;Name&#39;, &#39;Phone&#39;, &#39;S4&#39;, &#39;S2&#39;, &#39;S1&#39;, &#39;S3&#39;, &#39;S5&#39; ] df_insert = df_insert[insert_columns] # 重命名列以匹配实际表结构 column_mapping = {&#39;Phone&#39;: phone_field} df_insert = df_insert.rename(columns=column_mapping) # 定义插入列类型(包含CompanyName) insert_dtype = { phone_field: VARCHAR(15), # 指定电话列类型 &#39;S6&#39;: VARCHAR(50), &#39;CustomerTypeCode&#39;: VARCHAR(20), &#39;S5&#39;: VARCHAR(50), &#39;S1&#39;: VARCHAR(50), &#39;S2&#39;: VARCHAR(50), &#39;S3&#39;: VARCHAR(50), &#39;S4&#39;: VARCHAR(50), &#39;CompanyName&#39;: VARCHAR(100), # 新增字段类型 &#39;Name&#39;: VARCHAR(50) } # 批量插入新记录(分块处理) print(f"正在批量插入 {len(df_insert)} 条新记录...") df_insert.to_sql( &#39;T_Customer&#39;, mysql_engine, if_exists=&#39;append&#39;, index=False, chunksize=2000, # 分块插入提高性能 method=&#39;multi&#39;, # 使用多值插入 dtype=insert_dtype ) insert_duration = time.time() - start_time print(f"✅ 成功插入 {len(df_insert)} 条新记录 (耗时: {insert_duration:.2f}秒)") # 验证ID和GUID唯一性 id_check_query = "SELECT COUNT(*) AS total, COUNT(DISTINCT id) AS distinct_ids FROM T_Customer" guid_check_query = "SELECT COUNT(*) AS total, COUNT(DISTINCT GUID) AS distinct_guids FROM T_Customer" with mysql_engine.connect() as conn: # 验证ID唯一性 id_check = conn.execute(text(id_check_query)).fetchone() if id_check[0] == id_check[1]: print("✅ ID唯一性验证通过") else: print(f"❌ ID唯一性警告: 总数={id_check[0]}, 唯一数={id_check[1]}") # 验证GUID唯一性 guid_check = conn.execute(text(guid_check_query)).fetchone() if guid_check[0] == guid_check[1]: print("✅ GUID唯一性验证通过") else: print(f"❌ GUID唯一性警告: 总数={guid_check[0]}, 唯一数={guid_check[1]}") except Exception as e: print(f"❌ 插入操作失败: {str(e)}") # 记录错误详情 error_file = f"insert_error_{time.strftime(&#39;%Y%m%d_%H%M%S&#39;)}.log" with open(error_file, &#39;w&#39;) as f: f.write(f"错误时间: {time.strftime(&#39;%Y-%m-%d %H:%M:%S&#39;)}\n") f.write(f"错误信息: {str(e)}\n") f.write("部分插入数据:\n") if &#39;df_insert&#39; in locals(): f.write(df_insert.head().to_string()) print(f"错误详情已保存到: {error_file}") traceback.print_exc() # 15. 清理临时表 try: with mysql_engine.begin() as conn: conn.execute(text(f"DROP TABLE IF EXISTS {temp_table_name}")) print("✅ 临时表清理完成") except: print("⚠️ 临时表清理失败,请手动检查") # 16. 最终统计 print("\n" + "=" * 80) print("数据同步完成!") print(f"总耗时: {time.time() - start_time:.2f}秒") print(f"处理记录统计:") print(f" 一致记录: {stats[&#39;consistent_records&#39;]}") print(f" 更新记录: {len(updates_to_apply)}") print(f" 新增记录: {len(inserts_to_apply)}") print(f" 总处理记录: {stats[&#39;consistent_records&#39;] + len(updates_to_apply) + len(inserts_to_apply)}") print("=" * 80) if name == “main”: main() 修改代码 加一个对新增数据的去重 我的意思是 对即将插入的数据进行本身的去重
08-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值