cppackage 0.2.9__py3-none-any.whl → 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CPpackage/db/sql_model.py +56 -47
- CPpackage/db/test.py +6 -5
- {cppackage-0.2.9.dist-info → cppackage-0.3.1.dist-info}/METADATA +2 -12
- cppackage-0.3.1.dist-info/RECORD +13 -0
- {cppackage-0.2.9.dist-info → cppackage-0.3.1.dist-info}/WHEEL +1 -1
- cppackage-0.2.9.dist-info/RECORD +0 -13
- {cppackage-0.2.9.dist-info/licenses → cppackage-0.3.1.dist-info}/LICENSE +0 -0
- {cppackage-0.2.9.dist-info → cppackage-0.3.1.dist-info}/entry_points.txt +0 -0
- {cppackage-0.2.9.dist-info → cppackage-0.3.1.dist-info}/top_level.txt +0 -0
CPpackage/db/sql_model.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import pymysql
|
|
2
2
|
import time
|
|
3
3
|
from pymysql import Error
|
|
4
|
-
import pandas as pd
|
|
5
|
-
# 条件导入:支持直接运行和包模式
|
|
6
4
|
try:
|
|
7
5
|
from .config import get_db_config
|
|
8
6
|
except (ImportError, ValueError):
|
|
@@ -161,6 +159,13 @@ def find_duplicate_records(table_name, database, unique_index_fields, port=None)
|
|
|
161
159
|
"""
|
|
162
160
|
|
|
163
161
|
try:
|
|
162
|
+
# Lazy import pandas here to avoid heavy imports during module import
|
|
163
|
+
try:
|
|
164
|
+
import pandas as pd
|
|
165
|
+
except Exception as e:
|
|
166
|
+
print("无法导入 pandas:", e)
|
|
167
|
+
return None
|
|
168
|
+
|
|
164
169
|
with _get_connection(database, port) as conn:
|
|
165
170
|
df_duplicates = pd.read_sql(sql, conn)
|
|
166
171
|
if df_duplicates.empty:
|
|
@@ -168,8 +173,8 @@ def find_duplicate_records(table_name, database, unique_index_fields, port=None)
|
|
|
168
173
|
else:
|
|
169
174
|
print(f"发现 {len(df_duplicates)} 条重复记录({len(df_duplicates.drop_duplicates(subset=unique_index_fields))} 组重复组合)")
|
|
170
175
|
# 可选:保存重复记录到CSV
|
|
171
|
-
df_duplicates.to_csv(f"duplicate_records_{table_name}.csv", index=False, encoding="utf-8-sig")
|
|
172
|
-
print("重复记录已保存到 duplicate_records_{table_name}.csv")
|
|
176
|
+
# df_duplicates.to_csv(f"duplicate_records_{table_name}.csv", index=False, encoding="utf-8-sig")
|
|
177
|
+
# print("重复记录已保存到 duplicate_records_{table_name}.csv")
|
|
173
178
|
return df_duplicates
|
|
174
179
|
except pymysql.MySQLError as e:
|
|
175
180
|
print("数据库查询失败:", e)
|
|
@@ -178,7 +183,7 @@ def find_duplicate_records(table_name, database, unique_index_fields, port=None)
|
|
|
178
183
|
print("未知错误:", e)
|
|
179
184
|
return None
|
|
180
185
|
# ===================== 删除重复记录函数(修复参数+调用逻辑) =====================
|
|
181
|
-
def delete_duplicate_records(table_name, database, unique_index_fields, port=None, keep_strategy="
|
|
186
|
+
def delete_duplicate_records(table_name, database, unique_index_fields, port=None, keep_strategy="max_id"):
|
|
182
187
|
"""
|
|
183
188
|
删除重复记录,仅保留每组唯一值的一条记录
|
|
184
189
|
参数:
|
|
@@ -190,10 +195,6 @@ def delete_duplicate_records(table_name, database, unique_index_fields, port=Non
|
|
|
190
195
|
返回:
|
|
191
196
|
int: 删除的记录数;None: 出错;0: 无重复
|
|
192
197
|
"""
|
|
193
|
-
# 1. 先调用修复后的find_duplicate_records查询重复数据
|
|
194
|
-
duplicate_df = find_duplicate_records(table_name, database, unique_index_fields, port)
|
|
195
|
-
if duplicate_df is None or duplicate_df.empty:
|
|
196
|
-
return 0
|
|
197
198
|
|
|
198
199
|
# 2. 构建删除SQL(核心逻辑)
|
|
199
200
|
group_by_str = ",".join([f"`{field}`" for field in unique_index_fields])
|
|
@@ -243,43 +244,51 @@ def delete_duplicate_records(table_name, database, unique_index_fields, port=Non
|
|
|
243
244
|
return None
|
|
244
245
|
# ===================== DataFrame 入库 =====================
|
|
245
246
|
|
|
246
|
-
def update_datas(df, table_name, database):
|
|
247
|
-
|
|
248
|
-
conn = None
|
|
249
|
-
for i in range(2):
|
|
250
|
-
try:
|
|
251
|
-
conn = _get_connection(database)
|
|
252
|
-
cursor = conn.cursor()
|
|
253
|
-
cols = list(df.columns)
|
|
254
|
-
col_str = ",".join([f"`{c}`" for c in cols])
|
|
255
|
-
value_tpl = "(" + ",".join(["%s"] * len(cols)) + ")"
|
|
256
|
-
values_str = ",".join([value_tpl] * len(df))
|
|
257
|
-
update_clause = ",".join(
|
|
258
|
-
[f"`{c}`=VALUES(`{c}`)" for c in cols if c != "id"]
|
|
259
|
-
)
|
|
260
|
-
sql = f"""
|
|
261
|
-
INSERT INTO `{table_name}` ({col_str})
|
|
262
|
-
VALUES {values_str}
|
|
263
|
-
ON DUPLICATE KEY UPDATE {update_clause}
|
|
264
|
-
"""
|
|
265
|
-
print(sql)
|
|
266
|
-
data = [tuple(row) for row in df.values]
|
|
267
|
-
flat_data = [v for row in data for v in row]
|
|
268
|
-
cursor.execute(sql, flat_data)
|
|
269
|
-
conn.commit()
|
|
270
|
-
print(f"成功插入/更新 {cursor.rowcount} 条记录")
|
|
271
|
-
break
|
|
272
|
-
except Exception as e:
|
|
273
|
-
if conn:
|
|
274
|
-
conn.rollback()
|
|
275
|
-
print("入库失败:", e)
|
|
276
|
-
if '1054, "Unknown column' in str(e):
|
|
277
|
-
# 表结构校验,df为抓取数据表
|
|
278
|
-
check_and_sync_columns(df,table_name,database)
|
|
279
|
-
else:
|
|
280
|
-
raise Exception(e)
|
|
281
|
-
finally:
|
|
282
|
-
if conn:
|
|
283
|
-
conn.close()
|
|
247
|
+
def update_datas(df, table_name, database, batch_size=20):
|
|
284
248
|
|
|
249
|
+
if df.empty:
|
|
250
|
+
print("数据为空,无需入库")
|
|
251
|
+
return
|
|
252
|
+
cols = list(df.columns)
|
|
253
|
+
col_str = ",".join([f"`{c}`" for c in cols])
|
|
254
|
+
value_tpl = "(" + ",".join(["%s"] * len(cols)) + ")"
|
|
255
|
+
update_clause = ",".join(
|
|
256
|
+
[f"`{c}`=VALUES(`{c}`)" for c in cols if c != "id"]
|
|
257
|
+
)
|
|
258
|
+
total = len(df)
|
|
259
|
+
success_count = 0
|
|
260
|
+
for start in range(0, total, batch_size):
|
|
261
|
+
batch_df = df.iloc[start:start + batch_size]
|
|
262
|
+
values_str = ",".join([value_tpl] * len(batch_df))
|
|
263
|
+
sql = f"""
|
|
264
|
+
INSERT INTO `{table_name}` ({col_str})
|
|
265
|
+
VALUES {values_str}
|
|
266
|
+
ON DUPLICATE KEY UPDATE {update_clause}
|
|
267
|
+
"""
|
|
268
|
+
data = [tuple(row) for row in batch_df.values]
|
|
269
|
+
flat_data = [v for row in data for v in row]
|
|
270
|
+
conn = None
|
|
271
|
+
for attempt in range(2):
|
|
272
|
+
try:
|
|
273
|
+
conn = _get_connection(database)
|
|
274
|
+
cursor = conn.cursor()
|
|
275
|
+
cursor.execute(sql, flat_data)
|
|
276
|
+
conn.commit()
|
|
277
|
+
success_count += cursor.rowcount
|
|
278
|
+
break
|
|
279
|
+
except Exception as e:
|
|
280
|
+
if conn:
|
|
281
|
+
conn.rollback()
|
|
282
|
+
print(f"批次入库失败(start={start}):", e)
|
|
283
|
+
if '1054, "Unknown column' in str(e):
|
|
284
|
+
check_and_sync_columns(df, table_name, database)
|
|
285
|
+
break
|
|
286
|
+
elif attempt == 0:
|
|
287
|
+
time.sleep(1)
|
|
288
|
+
else:
|
|
289
|
+
raise Exception(e)
|
|
290
|
+
finally:
|
|
291
|
+
if conn:
|
|
292
|
+
conn.close()
|
|
293
|
+
print(f"成功插入/更新 {success_count} 条记录")
|
|
285
294
|
|
CPpackage/db/test.py
CHANGED
|
@@ -4,21 +4,22 @@ import os
|
|
|
4
4
|
|
|
5
5
|
if __name__ == "__main__":
|
|
6
6
|
# 配置你的参数
|
|
7
|
-
TABLE_NAME = "
|
|
8
|
-
DATABASE_NAME = "
|
|
7
|
+
TABLE_NAME = "pinlei_spph"
|
|
8
|
+
DATABASE_NAME = "shengyicanmou"
|
|
9
9
|
# 你的唯一索引字段列表(必须是列表类型!)
|
|
10
|
-
UNIQUE_FIELDS = [
|
|
10
|
+
UNIQUE_FIELDS = ["itemId", "store_id", "begindate", "value_l", "sellerId", "cateLevel2Id", "cateId", "cateLevel1Id", "mainProductId", "itemTag", "date_effect"]
|
|
11
11
|
PORT = 3306 # 可选,默认从配置获取
|
|
12
12
|
|
|
13
13
|
# 第一步:查询重复记录
|
|
14
14
|
dup_df = find_duplicate_records(TABLE_NAME, DATABASE_NAME, UNIQUE_FIELDS, PORT)
|
|
15
15
|
|
|
16
|
-
# 第二步:确认有重复后删除
|
|
16
|
+
# # 第二步:确认有重复后删除
|
|
17
17
|
if dup_df is not None and not dup_df.empty:
|
|
18
|
+
|
|
18
19
|
delete_count = delete_duplicate_records(
|
|
19
20
|
table_name=TABLE_NAME,
|
|
20
21
|
database=DATABASE_NAME,
|
|
21
22
|
unique_index_fields=UNIQUE_FIELDS, # 必须传列表!
|
|
22
23
|
port=PORT,
|
|
23
|
-
keep_strategy="
|
|
24
|
+
keep_strategy="max_id"
|
|
24
25
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: cppackage
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: 超品集团自用的Python包
|
|
5
5
|
Home-page: https://github.com/example/CPpackage
|
|
6
6
|
Author: team-数智组
|
|
@@ -20,16 +20,6 @@ License-File: LICENSE
|
|
|
20
20
|
Requires-Dist: pymysql
|
|
21
21
|
Requires-Dist: pandas
|
|
22
22
|
Requires-Dist: numpy
|
|
23
|
-
Dynamic: author
|
|
24
|
-
Dynamic: author-email
|
|
25
|
-
Dynamic: classifier
|
|
26
|
-
Dynamic: description
|
|
27
|
-
Dynamic: description-content-type
|
|
28
|
-
Dynamic: home-page
|
|
29
|
-
Dynamic: license-file
|
|
30
|
-
Dynamic: requires-dist
|
|
31
|
-
Dynamic: requires-python
|
|
32
|
-
Dynamic: summary
|
|
33
23
|
|
|
34
24
|
# CPpackage
|
|
35
25
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
CPpackage/__init__.py,sha256=KpVaXkIzkNDl-dfSX8Rr7z9XFlipxx1nZ_GzS4Qls4I,173
|
|
2
|
+
CPpackage/core/__init__.py,sha256=92mF0310uQ5ujlgd-LCMs5kZVzfGRdcl67GHIRWhHcA,504
|
|
3
|
+
CPpackage/db/__init__.py,sha256=WhrLqsjq97KKHF7YV-HcZf9pRtHuqKhRjXDNPCBVbjY,107
|
|
4
|
+
CPpackage/db/config.py,sha256=A9HFCXqlrvssHLD1Ys9HpjDckavalFj31X1Np_aDNp4,729
|
|
5
|
+
CPpackage/db/sql_model.py,sha256=QnWEBb-ZqioZf62q-RQPgG8uJqLY9KgcyGW3zFkH4YY,10198
|
|
6
|
+
CPpackage/db/test.py,sha256=dEeoV5FBuWEt5MFujrt3fd2KSQ690zyw6mANgeiVRCg,1015
|
|
7
|
+
CPpackage/utils/__init__.py,sha256=sAespT0aoLr3O0WF27DwHLYF60VZgPA1tiT0JJ8s8zI,264
|
|
8
|
+
cppackage-0.3.1.dist-info/LICENSE,sha256=6Pj597LnvlRtq3Vgjkfp6zgBeBh7wl8jKE-nCFg4vZI,1065
|
|
9
|
+
cppackage-0.3.1.dist-info/METADATA,sha256=UZsPKX3T4zA7FbzYpb6Ppy0UvjzFjgq5zXMmZmFjqnE,2287
|
|
10
|
+
cppackage-0.3.1.dist-info/WHEEL,sha256=hPN0AlP2dZM_3ZJZWP4WooepkmU9wzjGgCLCeFjkHLA,92
|
|
11
|
+
cppackage-0.3.1.dist-info/entry_points.txt,sha256=SAzF2klkNyeNCqXuiNkDirN999l7v8CGCrHR0StD_oo,50
|
|
12
|
+
cppackage-0.3.1.dist-info/top_level.txt,sha256=FQrfWDbJistWQIrHW_Aoxoy_UWSzjOByWVcVS5ig9Tk,10
|
|
13
|
+
cppackage-0.3.1.dist-info/RECORD,,
|
cppackage-0.2.9.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
CPpackage/__init__.py,sha256=KpVaXkIzkNDl-dfSX8Rr7z9XFlipxx1nZ_GzS4Qls4I,173
|
|
2
|
-
CPpackage/core/__init__.py,sha256=92mF0310uQ5ujlgd-LCMs5kZVzfGRdcl67GHIRWhHcA,504
|
|
3
|
-
CPpackage/db/__init__.py,sha256=WhrLqsjq97KKHF7YV-HcZf9pRtHuqKhRjXDNPCBVbjY,107
|
|
4
|
-
CPpackage/db/config.py,sha256=A9HFCXqlrvssHLD1Ys9HpjDckavalFj31X1Np_aDNp4,729
|
|
5
|
-
CPpackage/db/sql_model.py,sha256=tF31cF1SADulPGQ0TWcqhKOE393hdL4TMe6Xycv44UA,9942
|
|
6
|
-
CPpackage/db/test.py,sha256=XzPTllM5S4s7M4NHJ_i4h_ZEEalnDTWhGd7d__nUS10,1011
|
|
7
|
-
CPpackage/utils/__init__.py,sha256=sAespT0aoLr3O0WF27DwHLYF60VZgPA1tiT0JJ8s8zI,264
|
|
8
|
-
cppackage-0.2.9.dist-info/licenses/LICENSE,sha256=6Pj597LnvlRtq3Vgjkfp6zgBeBh7wl8jKE-nCFg4vZI,1065
|
|
9
|
-
cppackage-0.2.9.dist-info/METADATA,sha256=TaYeSok8htlPG0vIGSHkffQemPNolIT_koOk5B3mqpw,2516
|
|
10
|
-
cppackage-0.2.9.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
11
|
-
cppackage-0.2.9.dist-info/entry_points.txt,sha256=SAzF2klkNyeNCqXuiNkDirN999l7v8CGCrHR0StD_oo,50
|
|
12
|
-
cppackage-0.2.9.dist-info/top_level.txt,sha256=FQrfWDbJistWQIrHW_Aoxoy_UWSzjOByWVcVS5ig9Tk,10
|
|
13
|
-
cppackage-0.2.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|