使用ROW_NUMBER()查询:列名 'RowNumber' 无效。(转载)

本文探讨了在 SQL 查询中使用 ROW_NUMBER() 函数时遇到的常见错误,并提供了一种解决方法。通过包裹额外的子查询,可以避免直接在查询结果集中使用刚定义的 RowNumber 列名所导致的问题。

原文地址:https://my.oschina.net/wangzan/blog/202456

使用ROW_NUMBER()方法查询结果集;语句如下:

 
select ROW_NUMBER() OVER(ORDER BY dbo.OrderOutProduct.ID) AS RowNumber,
 dbo.Order.ID,Telephone,AddressCity,Province, from dbo.Order 
inner join dbo.Order2
on dbo.Order.ID=Order2ID
inner join dbo.Order3
on dbo.Order2.OrderID=dbo.Order3.Order3
where Service=1 and RowNumber=1

但是出现了错误:列名 'RowNumber' 无效。

image

查到网上给的解释是:在sql里这个叫做,热名称,刚定的不能立马使用!要包一层查询!

修改为:

select * from(
select ROW_NUMBER() OVER(ORDER BY dbo.OrderOutProduct.ID) AS RowNumber,
dbo.Order.ID,Telephone,AddressCity,Province, from dbo.Order 
inner join dbo.Order2
on dbo.Order.ID=Order2ID
inner join dbo.Order3
on dbo.Order2.OrderID=dbo.Order3.Order3
where Service=1 
)U where RowNumber=1


import os import glob import zipfile from openpyxl import load_workbook, Workbook from openpyxl.drawing.image import Image from openpyxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor, OneCellAnchor from openpyxl.styles import PatternFill, Border, Side, Alignment, Font, colors from openpyxl.utils import get_column_letter import copy import re def is_valid_excel_file(file_path): """检查是否为有效的Excel文件""" try: with zipfile.ZipFile(file_path, 'r') as zip_ref: required_files = ['xl/workbook.xml', 'xl/styles.xml', 'xl/worksheets/'] return all(name in zip_ref.namelist() for name in required_files[:-1]) except zipfile.BadZipFile: return False except Exception: return False def copy_cell_style(src_cell, dest_cell): """复制单元格样式""" if src_cell.font: dest_cell.font = copy.copy(src_cell.font) if src_cell.fill: dest_cell.fill = copy.copy(src_cell.fill) if src_cell.border: dest_cell.border = copy.copy(src_cell.border) if src.cell.alignment: dest_cell.alignment = copy.copy(src_cell.alignment) if src_cell.number_format: dest_cell.number_format = src_cell.number_format def find_passport_column(ws): """ 查找包含'passport'关键字的列(不区分大小写) 返回列字母和列索引(从1开始) """ # 检查第一行(通常是标题行) for cell in ws[1]: if cell.value and re.search(r'passport', str(cell.value), re.IGNORECASE): return cell.column_letter, cell.column # 如果第一行没找到,检查所有单元格 for row in ws.iter_rows(min_row=1, max_row=min(10, ws.max_row)): for cell in row: if cell.value and re.search(r'passport', str(cell.value), re.IGNORECASE): return cell.column_letter, cell.column # 仍未找到,默认第一列 return 'A', 1 def create_header_style(): """创建第一列的标题样式""" return ( Font(bold=True, color=colors.WHITE), PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid"), Alignment(horizontal='center', vertical='center') ) def merge_excel_with_deduplication(input_dir, output_file): """ 合并Excel文件并基于Passport字段去重 保留格式和图片,第一列添加文件名和工作表名 """ # 创建新工作簿 wb_output = Workbook() ws_output = wb_output.active ws_output.title = "Merged Deduplicated" # 创建第一列标题的样式 header_font, header_fill, header_alignment = create_header_style() ws_output.column_dimensions['A'].width = 40 # 存储所有已处理的Passport值 seen_passports = set() # 存储行数据和图片信息:(passport_value, row_data, images_list, has_image) all_rows = [] # 存储列名映射关系 column_mapping = {} # 第一阶段:收集所有数据并进行预处理 try: for excel_file in glob.glob(os.path.join(input_dir, "*.xlsx")): file_name = os.path.basename(excel_file) if not is_valid_excel_file(excel_file): print(f"跳过无效文件: {file_name}") continue print(f"处理文件: {file_name}") try: wb_source = load_workbook(excel_file, keep_vba=False, data_only=True) except Exception as e: print(f" 加载失败: {str(e)}") continue for ws_name in wb_source.sheetnames: print(f" 处理工作表: {ws_name}") ws_source = wb_source[ws_name] # 1. 查找Passport列 passport_col_letter, passport_col_idx = find_passport_column(ws_source) print(f" 检测到Passport列: {passport_col_letter}") # 2. 收集图片信息 image_rows = {} if hasattr(ws_source, '_images'): for img in ws_source._images: # 获取图片所在行 if isinstance(img.anchor, (TwoCellAnchor, OneCellAnchor)): anchor = img.anchor img_row = anchor._from.row if hasattr(anchor, '_from') else anchor.row if img_row not in image_rows: image_rows[img_row] = [] image_rows[img_row].append(img) # 3. 处理每一行数据 for row_idx, row in enumerate(ws_source.iter_rows(), 1): passport_cell = ws_source.cell(row=row_idx, column=passport_col_idx) passport_value = str(passport_cell.value).strip() if passport_cell.value else "" # 跳过空Passport行 if not passport_value: continue has_image = row_idx in image_rows # 收集行数据 row_data = [] for cell in row: cell_data = { 'value': cell.value, 'font': copy.copy(cell.font), 'fill': copy.copy(cell.fill), 'border': copy.copy(cell.border), 'alignment': copy.copy(cell.alignment), 'number_format': cell.number_format } row_data.append(cell_data) # 记录列名映射(仅第一行) if row_idx == 1: for col_idx, cell in enumerate(row, 1): col_name = cell.value if cell.value else f"Column{col_idx}" column_mapping[col_idx] = col_name # 添加文件信息 source_info = f"{file_name}-{ws_name}" # 添加到所有行集合 all_rows.append({ 'passport': passport_value, 'source_info': source_info, 'row_data': row_data, 'images': image_rows.get(row_idx, []), 'has_image': has_image, 'row_idx': row_idx, 'file': file_name, 'sheet': ws_name }) except Exception as e: print(f"收集数据时出错: {str(e)}") raise # 第二阶段:基于Passport去重 print("\n开始去重处理...") passport_groups = {} for row in all_rows: passport = row['passport'] if passport not in passport_groups: passport_groups[passport] = [] passport_groups[passport].append(row) # 按规则选择保留的行 dedup_rows = [] for passport, rows in passport_groups.items(): # 查找有图片的行 rows_with_images = [r for r in rows if r['has_image']] if rows_with_images: # 保留第一个有图片的行 dedup_rows.append(rows_with_images[0]) if len(rows_with_images) > 1: print(f" Passport {passport}: 保留有图片的第一行(共有 {len(rows_with_images)} 行含图片)") else: # 保留第一行 dedup_rows.append(rows[0]) print(f" Passport {passport}: 保留第一行(无图片行)") print(f"去重完成: 原始 {len(all_rows)} 行 -> 去重后 {len(dedup_rows)} 行") # 第三阶段:写入输出文件 current_row = 1 image_offset = 0 # 图片行偏移量 # 写入标题行 ws_output.cell(row=current_row, column=1, value="Source").font = header_font ws_output.cell(row=current_row, column=2, value="Passport").font = header_font for col_idx, col_name in column_mapping.items(): ws_output.cell(row=current_row, column=col_idx+2, value=col_name).font = header_font current_row += 1 # 写入数据行 for row_data in dedup_rows: # 添加源信息列 source_cell = ws_output.cell(row=current_row, column=1) source_cell.value = row_data['source_info'] source_cell.font = header_font source_cell.fill = header_fill source_cell.alignment = header_alignment # 添加Passport列 passport_cell = ws_output.cell(row=current_row, column=2) passport_cell.value = row_data['passport'] # 添加其他列数据 for col_idx, cell_data in enumerate(row_data['row_data'], 1): dest_cell = ws_output.cell(row=current_row, column=col_idx+2) dest_cell.value = cell_data['value'] # 应用样式 if cell_data['font']: dest_cell.font = cell_data['font'] if cell_data['fill']: dest_cell.fill = cell_data['fill'] if cell_data['border']: dest_cell.border = cell_data['border'] if cell_data['alignment']: dest_cell.alignment = cell_data['alignment'] if cell_data.get('number_format'): dest_cell.number_format = cell_data['number_format'] # 处理图片 if row_data['has_image']: for img in row_data['images']: img_copy = copy.deepcopy(img) anchor = img_copy.anchor # 调整锚点位置 if isinstance(anchor, TwoCellAnchor): new_anchor = TwoCellAnchor( _from=AnchorMarker( col=anchor._from.col + 2, # 新增了两列 row=anchor._from.row + current_row - row_data['row_idx'] - 1, colOff=anchor._from.colOff, rowOff=anchor._from.rowOff ), to=AnchorMarker( col=anchor.to.col + 2, # 新增了两列 row=anchor.to.row + current_row - row_data['row_idx'] - 1, colOff=anchor.to.colOff, rowOff=anchor.to.rowOff ) ) img_copy.anchor = new_anchor elif isinstance(anchor, OneCellAnchor): new_anchor = OneCellAnchor( _from=AnchorMarker( col=anchor._from.col + 2, # 新增了两列 row=anchor._from.row + current_row - row_data['row_idx'] - 1, colOff=anchor._from.colOff, rowOff=anchor._from.rowOff ) ) img_copy.anchor = new_anchor # 添加图片 ws_output.add_image(img_copy) current_row += 1 # 保存结果 try: wb_output.save(output_file) print(f"\n合并完成! 输出文件: {output_file}") print(f"原始行数: {len(all_rows)}, 去重后行数: {len(dedup_rows)}") except Exception as e: print(f"保存文件时出错: {str(e)}") raise if __name__ == "__main__": input_directory = "./input_excels" # Excel文件所在目录 output_filename = "merged_deduplicated.xlsx" merge_excel_with_deduplication(input_directory, output_filename) 这个代码图片图片会错位和缺失,修正下
最新发布
10-05
import os import sqlite3 import shutil import tempfile import time from datetime import datetime, timedelta from pathlib import Path import mysql.connector from ping3 import ping # ======================== # 配置区域 # ======================== # 全局最小时间门槛(不会早于这个时间同步) MIN_TIME = '2025-09-01 00:00:00' # 分播机配置:IP -> (LineNumber, 数据库UNC路径或映射路径) SORTERS = { '192.168.110.56': (1, r'Y:\sorting.db'), # 示例:也可写成 r'\\192.168.110.56\share\sorting.db' '192.168.110.60': (9, r'Z:\sorting.db'), } # MySQL 配置 MYSQL_CONFIG = { 'host': 'localhost', 'user': 'admin', 'password': 'gapinyc', 'database': 'board_db', 'auth_plugin': 'mysql_native_password', 'charset': 'utf8mb4' } # 要同步的表名列表 TABLES_TO_SYNC = [ 'AppSortingTasks', # 最顶层(无外部依赖) 'AppOperationLogs', # 可能依赖 Tasks,也可能独立 'AppReportRecords', # 通常独立或依赖 Tasks 'AppSortingTaskItems', # 依赖 Tasks 'AppSortingTaskImages', # 通常依赖 Items 或 Tasks 'AppSortingTaskSkus', # 依赖 Items 'AppSortingTaskBoxes' # 可能依赖 Items 或 Tasks ] # ======================== # 工具函数 # ======================== def is_valid_sqlite_db(file_path): """检查文件是否为有效的 SQLite 数据库""" try: with open(file_path, 'rb') as f: header = f.read(16) return header == b'SQLite format 3\x00' except Exception as e: print(f"[CHECK ERROR] 无法读取文件头 {file_path}: {e}") return False def is_file_accessible(path_str): """检测共享路径上的数据库文件是否存在且可读""" try: db_path = Path(path_str) if not db_path.exists(): print(f"[PATH ERROR] 文件不存在: {db_path}") return False if not db_path.is_file(): print(f"[PATH ERROR] 路径不是文件: {db_path}") return False if db_path.stat().st_size == 0: print(f"[PATH ERROR] 文件大小为0字节: {db_path}") return False return True except Exception as e: print(f"[PATH ERROR] 访问路径异常 {path_str}: {e}") return False def connect_sqlite_remote_safely(db_path): """ 安全连接远程 SQLite 数据库:先复制到本地临时文件再打开 返回: (connection, temp_db_path) 元组 或 (None, None) """ temp_db = None try: # 创建临时文件 with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as tmp: temp_db = tmp.name print(f"📥 正在复制数据库: {db_path} → {temp_db}") shutil.copy2(db_path, temp_db) # 验证副本是否为有效 SQLite 文件 if not is_valid_sqlite_db(temp_db): print(f"[ERROR] 复制后的数据库无效: {temp_db}") os.unlink(temp_db) return None, None # 尝试连接 conn = sqlite3.connect(f'file:{temp_db}?mode=ro', uri=True, timeout=10.0) conn.row_factory = sqlite3.Row # 支持按列名访问 print(f"✅ 成功加载数据库副本: {temp_db}") return conn, temp_db # 成功则返回 conn 和路径 except Exception as e: print(f"[ERROR] 复制或连接数据库失败 {db_path}: {e}") # 清理临时文件(如果存在) if temp_db and os.path.exists(temp_db): try: os.unlink(temp_db) print(f"🗑️ 清理失败的临时数据库: {temp_db}") except Exception as clean_e: print(f"[WARN] 无法删除临时文件 {temp_db}: {clean_e}") return None, None def close_sqlite_connection(conn, temp_db_path): """安全关闭 SQLite 连接并删除临时文件""" if conn: try: conn.close() print("🔒 SQLite 连接已关闭") except Exception as e: print(f"[WARN] 关闭 SQLite 连接时出错: {e}") # 删除临时文件 if temp_db_path and os.path.exists(temp_db_path): try: os.unlink(temp_db_path) print(f"🗑️ 已删除临时数据库: {temp_db_path}") except Exception as e: print(f"[WARN] 无法删除临时文件 {temp_db_path}: {e}") def sync_table_from_sqlite_to_mysql(sorter_ip, line_number, sqlite_path, mysql_conn, table_name): sqlite_conn = None temp_db = None mysql_cursor = None try: if not is_file_accessible(sqlite_path): print(f"[FAIL] 源文件不可访问: {sqlite_path}") return False # ✅ 新式解包返回值 sqlite_conn, temp_db = connect_sqlite_remote_safely(sqlite_path) if not sqlite_conn: print(f"[FAIL] 无法安全打开数据库: {sqlite_path}") return False mysql_cursor = mysql_conn.cursor() target_table = f"AI_{table_name}" twelve_hours_ago = (datetime.now() - timedelta(hours=12)).strftime('%Y-%m-%d %H:%M:%S') filter_time = max(MIN_TIME, twelve_hours_ago) print(f" 🕒 同步时间窗口起点: {filter_time}") query = f"SELECT * FROM `{table_name}` WHERE creationtime >= ?" try: rows = list(sqlite_conn.execute(query, (filter_time,))) except sqlite3.Error as e: print(f"[ERROR] 查询表 {table_name} 出错: {e}") return False if not rows: print(f" ⚠️ 表 {table_name} 无符合 creationtime >= '{filter_time}' 的数据") return True print(f" 📥 从 {table_name} 读取到 {len(rows)} 条数据") # === DEBUG: 打印原始 keys === raw_keys = rows[0].keys() print(f"🔍 原始列名列表: {raw_keys}") # 检查是否有非法列名 for k in raw_keys: if not isinstance(k, str): print(f"[WARN] 非字符串列名: {k} (类型: {type(k)})") if k.strip() == 'I': print(f"[CRITICAL] 发现危险列名: '{k}' ← 这会导致 SQL 错误!") if not k.isidentifier(): print(f"[WARN] 非法标识符列名: '{k}'") columns = [k for k in raw_keys] all_columns_with_lineno = columns + ['LineNumber'] placeholders = ', '.join(['%s'] * len(all_columns_with_lineno)) insert_columns = ', '.join([f"`{col}`" for col in all_columns_with_lineno]) update_assignments = ', '.join([f"`{col}` = VALUES(`{col}`)" for col in all_columns_with_lineno]) insert_sql = f""" INSERT INTO {target_table} ({insert_columns}) VALUES ({placeholders}) ON DUPLICATE KEY UPDATE {update_assignments} """ data_to_insert = [tuple(list(row) + [line_number]) for row in rows] mysql_cursor.execute("START TRANSACTION") three_hours_ago = (datetime.now() - timedelta(hours=3)).strftime('%Y-%m-%d %H:%M:%S') delete_sql = f"DELETE FROM {target_table} WHERE creationtime >= %s" mysql_cursor.execute(delete_sql, (three_hours_ago,)) deleted_count = mysql_cursor.rowcount if deleted_count > 0: print(f" [TRUNCATE] 删除 {target_table} 中 {deleted_count} 条旧记录 (>= {three_hours_ago})") mysql_cursor.executemany(insert_sql, data_to_insert) inserted_count = mysql_cursor.rowcount mysql_conn.commit() print(f" ✅ 成功向 {target_table} 插入/更新 {inserted_count} 条数据") return True except Exception as e: print(f"[ERROR] 同步表 {table_name} 时发生异常: {e}") if mysql_conn: mysql_conn.rollback() return False finally: close_sqlite_connection(sqlite_conn, temp_db) # ✅ 显式传递 temp_db if mysql_cursor: mysql_cursor.close() def check_sorter_online(ip): """检查 IP 是否可达""" try: delay = ping(ip, timeout=2) return delay is not None except: return False def sync_single_sorter(ip, line_number, sqlite_path): """同步一台分播机的所有表""" print(f"\n🔍 开始检查分播机 Line{line_number} ({ip})...") if not check_sorter_online(ip): print(f"🔴 分播机 Line{line_number} ({ip}) 网络不通") return False print(f"✅ 分播机 Line{line_number} ({ip}) 网络通畅") if not is_file_accessible(sqlite_path): print(f"❌ 分播机数据库文件不可访问: {sqlite_path}") return False print(f"✅ 分播机数据库文件正常: {sqlite_path}") success = True mysql_conn = None try: mysql_conn = mysql.connector.connect(**MYSQL_CONFIG) if not mysql_conn.is_connected(): print("[FAIL] 无法连接到MySQL") return False for table_name in TABLES_TO_SYNC: result = sync_table_from_sqlite_to_mysql(ip, line_number, sqlite_path, mysql_conn, table_name) if not result: print(f"⚠️ 同步表 {table_name} 失败") success = False except Exception as e: print(f"[ERROR] MySQL 操作异常: {e}") success = False finally: if mysql_conn and mysql_conn.is_connected(): mysql_conn.close() if success: print(f"🟢 分播机 Line{line_number} 所有表同步成功") else: print(f"🔴 分播机 Line{line_number} 部分表同步失败") return success def main(): """主函数:遍历所有分播机进行同步""" print("🚀 开始执行分播机数据同步任务...") overall_success = True for ip, (line_number, db_path) in SORTERS.items(): try: result = sync_single_sorter(ip, line_number, db_path) if not result: overall_success = False except Exception as e: print(f"[CRITICAL] 同步分播机 {ip} 时发生未捕获异常: {e}") overall_success = False print("\n" + ("✅" if overall_success else "❌") + " 全部同步任务完成") if __name__ == "__main__": main() 改造以上代码,解决处理每个表都要重新复制和加载数据库,请提供完整代码
09-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值