create table ,data limit check

本文介绍了一个用于创建维护用户访问记录的数据库表的过程。该表包括月份数字标识、交易金额、访客访问金额(美元和人民币)、罚款金额等字段,并定义了审核标志、审核者、审核时间戳等元数据字段。
EXEC pkg_dwh_common_proc.stpr_dwh_drop_tbl('tbl_maprg_pp_vst_usr_maint_u', 'N');

CREATE TABLE tbl_maprg_pp_vst_usr_maint_u
(
month number(6,0) unique NOT NULL, --整数
txn_amt number NOT NULL,
guest_vst_amt_usd number NOT NULL,
guest_vst_amt_cny number NOT NULL,
pnlty_amt number NOT NULL,
APROV_FLG VARCHAR2(1),
APROV_BY VARCHAR2(30),
APROV_TS DATE,
LST_UPDATED_BY VARCHAR2(30),
LST_UPDATED_TS DATE,
check(month>200000 and month<300000)
)
pctfree 0
tablespace TBS_MAPG_OUT_MEDIUM
nologging;

commit;
import psycopg2 import pyodbc import re import logging import time import schedule import concurrent.futures from datetime import datetime from typing import List, Dict, Tuple, Any, Union, Optional, Set from queue import Queue import threading import os # 配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # 定义数据源配置(包含多个表) TABLE_NAMES = ["line1block", "line1cam", "line1crank", "line1head", "line1hsg", "line2block", "line2cam", "line2crank", "line2head"] # 添加需要处理的表名 # 重构数据源配置(添加主机IP) DATA_SOURCES = [] for table_name in TABLE_NAMES: # 192.168.154.11 主机 DATA_SOURCES.append({ 'type': 'postgresql', 'host': '192.168.154.11', 'port': '5432', 'database': 'andondata', 'user': 'powertrain', 'password': 'andromeda', 'table': table_name, 'host_ip': '192.168.154.11' # 显式存储IP用于映射 }) # 192.168.151.11 主机 DATA_SOURCES.append({ 'type': 'postgresql', 'host': '192.168.151.11', 'port': '5432', 'database': 'andondata', 'user': 'powertrain', 'password': 'andromeda', 'table': table_name, 'host_ip': '192.168.151.11' # 显式存储IP用于映射 }) # SQL Server目标配置 TARGET_CONFIG = { 'server': '192.168.10.116', 'database': '现场DB', 'username': 'sa', 'password': 'gtec_6600' } # 地址校验结果表配置 CHECK_RESULT_TABLE = "dwd_web安东状态" # 数据库连接重试配置 DB_RETRY_CONFIG = { 'max_retries': 3, 'delay': 5 # seconds } # 连接池配置 MAX_POOL_SIZE = 20 postgres_pools = {} sqlserver_pool = None sqlserver_pool_lock = threading.Lock() postgres_pool_locks = {} # 预编译正则表达式 ADDRESS_VALUE_PATTERN = re.compile(r'[\{\[]\s*[\{\[]?\s*"?([^,"\s]+)"?\s*,\s*"?([^,"\}\]]+)"?\s*[\}\]]?\s*[\}\]]') class SimpleConnectionPool: """简单的数据库连接池实现""" def __init__(self, create_func, max_size=10): self.create_func = create_func self.max_size = max_size self.pool = Queue(maxsize=max_size) self.lock = threading.Lock() self.connections_created = 0 def get_connection(self): """从连接池获取连接""" try: # 尝试从队列中获取现有连接 if not self.pool.empty(): return self.pool.get_nowait() # 如果未达到最大连接数,创建新连接 with self.lock: if self.connections_created < self.max_size: conn = self.create_func() self.connections_created += 1 return conn except: pass # 如果队列为空且达到最大连接数,等待连接释放 return self.pool.get() def release_connection(self, conn): """释放连接回连接池""" try: self.pool.put_nowait(conn) except: # 如果队列已满,关闭连接 try: conn.close() except: pass def create_sqlserver_connection(): """创建SQL Server连接""" conn_str = ( f"DRIVER={{ODBC Driver 17 for SQL Server}};" f"SERVER={TARGET_CONFIG['server']};" f"DATABASE={TARGET_CONFIG['database']};" f"UID={TARGET_CONFIG['username']};" f"PWD={TARGET_CONFIG['password']}" ) return pyodbc.connect(conn_str) def create_postgres_connection(host, port, database, user, password): """创建PostgreSQL连接""" return psycopg2.connect( host=host, port=port, database=database, user=user, password=password ) def init_connection_pools(): """初始化数据库连接池""" global sqlserver_pool # 创建SQL Server连接池 try: sqlserver_pool = SimpleConnectionPool( create_func=create_sqlserver_connection, max_size=MAX_POOL_SIZE ) logger.info("SQL Server连接池初始化成功") except Exception as e: logger.error(f"SQL Server连接池初始化失败: {str(e)}") sqlserver_pool = None # 创建PostgreSQL连接池(按主机分组) unique_hosts = set(source['host'] for source in DATA_SOURCES) for host in unique_hosts: source = next(s for s in DATA_SOURCES if s['host'] == host) try: create_func = lambda h=host: create_postgres_connection( host=source['host'], port=source['port'], database=source['database'], user=source['user'], password=source['password'] ) pool = SimpleConnectionPool( create_func=create_func, max_size=MAX_POOL_SIZE ) postgres_pools[host] = pool logger.info(f"PostgreSQL连接池初始化成功: {host}") except Exception as e: logger.error(f"PostgreSQL连接池初始化失败 ({host}): {str(e)}") postgres_pools[host] = None def get_db_connection(config: Dict, db_type: str): """从连接池获取数据库连接""" if db_type == 'postgresql' and config['host'] in postgres_pools and postgres_pools[config['host']]: try: return postgres_pools[config['host']].get_connection() except Exception as e: logger.error(f"从连接池获取PostgreSQL连接失败: {str(e)}") # 回退到直接连接 for attempt in range(DB_RETRY_CONFIG['max_retries']): try: if db_type == 'postgresql': return psycopg2.connect( host=config['host'], port=config['port'], database=config['database'], user=config['user'], password=config['password'] ) elif db_type == 'sqlserver': return pyodbc.connect( f"DRIVER={{ODBC Driver 17 for SQL Server}};" f"SERVER={config['server']};" f"DATABASE={config['database']};" f"UID={config['username']};" f"PWD={config['password']}" ) except Exception as e: logger.warning(f"数据库连接失败(尝试 {attempt + 1}/{DB_RETRY_CONFIG['max_retries']}): {str(e)}") time.sleep(DB_RETRY_CONFIG['delay']) raise ConnectionError(f"无法连接到数据库: {config}") def release_db_connection(conn, config: Dict, db_type: str): """释放数据库连接回连接池""" try: if db_type == 'postgresql' and config['host'] in postgres_pools and postgres_pools[config['host']]: postgres_pools[config['host']].release_connection(conn) elif db_type == 'sqlserver' and sqlserver_pool: sqlserver_pool.release_connection(conn) else: try: conn.close() except: pass except Exception as e: logger.error(f"释放数据库连接失败: {str(e)}") try: conn.close() except: pass def get_address_set(target_config: Dict) -> Set[str]: """获取所有需要校验的地址集合(使用连接池)""" conn = None try: conn = get_db_connection(target_config, 'sqlserver') cursor = conn.cursor() # 查询所有地址 cursor.execute("SELECT DISTINCT 地址 FROM T_web安东地址 WHERE 项目='状态' and 线组='加工' ") addresses = set() for row in cursor.fetchall(): addr = row[0] if addr: addresses.add(addr.strip()) logger.info(f"成功获取 {len(addresses)} 个需要校验的地址") return addresses except Exception as e: logger.error(f"获取地址集合失败: {str(e)}") return set() finally: if conn: release_db_connection(conn, target_config, 'sqlserver') def extract_data(source_config: Dict) -> List[Tuple]: """从指定数据源抽取数据(使用连接池)""" logger.info(f"从 {source_config['host']}.{source_config['table']} 抽取数据...") conn = None try: conn = get_db_connection(source_config, source_config['type']) cursor = conn.cursor() # 使用参数化查询防止SQL注入 query = f""" SELECT data, "createdAt" FROM {source_config['table']} WHERE "createdAt" > CURRENT_TIMESTAMP - INTERVAL '5 minutes' ORDER BY "createdAt" DESC LIMIT 1 """ cursor.execute(query) data = cursor.fetchall() logger.info(f"获取 {len(data)} 条记录") return data except Exception as e: logger.error(f"数据抽取失败: {str(e)}") return [] finally: if conn: release_db_connection(conn, source_config, source_config['type']) def fast_check_address_value( value_data: Any, address: str ) -> int: """快速检查地址值是否符合条件(第8位和第16位同时为1)""" try: # 1. 处理None值 if value_data is None: return 0 # 2. 直接处理整数类型 if isinstance(value_data, int): # 获取第8位(从0开始计数,第7位)和第16位(第15位) bit8 = (value_data >> 7) & 1 bit16 = (value_data >> 15) & 1 return 1 if bit8 == 1 and bit16 == 1 else 0 # 3. 尝试转换为整数处理 if isinstance(value_data, str): # 移除所有空白字符 clean_value = re.sub(r'\s+', '', value_data) # 如果只包含数字,尝试转换为整数 if clean_value.isdigit(): try: int_value = int(clean_value) bit8 = (int_value >> 7) & 1 bit16 = (int_value >> 15) & 1 return 1 if bit8 == 1 and bit16 == 1 else 0 except (ValueError, OverflowError): pass # 回退到字符串处理 # 确保长度为16位(不足补0,超过则截断) if len(clean_value) < 16: clean_value = clean_value.zfill(16) elif len(clean_value) > 16: clean_value = clean_value[:16] # 检查第8位(索引7)和第16位(索引15) bit8 = clean_value[7] if len(clean_value) > 7 else '0' bit16 = clean_value[15] if len(clean_value) > 15 else '0' # 如果第8位和第16位都为1,则返回1,否则返回0 return 1 if bit8 == '1' and bit16 == '1' else 0 # 4. 其他类型转换为字符串处理 value_str = str(value_data).strip() clean_value = re.sub(r'\s+', '', value_str) if len(clean_value) < 16: clean_value = clean_value.zfill(16) elif len(clean_value) > 16: clean_value = clean_value[:16] bit8 = clean_value[7] if len(clean_value) > 7 else '0' bit16 = clean_value[15] if len(clean_value) > 15 else '0' return 1 if bit8 == '1' and bit16 == '1' else 0 except Exception as e: logger.error(f"地址校验错误: {address}: {str(e)}") return -1 # 错误标志 def process_source_data( data: Any, created_at: datetime, address_set: Set[str], source_ip: str, source_table: str ) -> Union[Tuple, None]: """处理单个数据源的数据并返回校验结果(优化版)""" overall_result = 0 found_address = False # 优化列表处理 if isinstance(data, list): for item in data: # 跳过无效项 if not isinstance(item, list) or len(item) < 2: continue address = str(item[0]).strip() if item[0] is not None else "" # 快速跳过不在地址集的项 if not address or address not in address_set: continue found_address = True result = fast_check_address_value(item[1], address) if result == 1: overall_result = 1 break # 找到一个满足条件的地址即可 elif result == -1: continue # 优化字符串处理 elif isinstance(data, (str, bytes)): raw_str = data.decode('utf-8', errors='ignore') if isinstance(data, bytes) else data # 使用预编译的正则表达式匹配模式 matches = ADDRESS_VALUE_PATTERN.findall(raw_str) for match in matches: if len(match) < 2: continue address = match[0].strip() value_data = match[1].strip() # 快速跳过不在地址集的项 if not address or address not in address_set: continue found_address = True result = fast_check_address_value(value_data, address) if result == 1: overall_result = 1 break # 找到一个满足条件的地址即可 elif result == -1: continue # 优化字典处理 elif isinstance(data, dict): # 尝试多种可能的键名 address = "" for key in ['code', 'Code', 'address', 'Address']: if key in data: address = str(data[key]).strip() break # 快速跳过不在地址集的项 if not address or address not in address_set: return None found_address = True # 查找值 value_data = None for key in ['bin', 'Bin', 'value', 'Value', 'data', 'Data']: if key in data: value_data = data[key] break if value_data is None: logger.warning(f"字典数据中未找到有效的值字段: {data}") return None result = fast_check_address_value(value_data, address) if result == 1: overall_result = 1 # 如果没有找到任何地址在集合中,则返回None if not found_address: logger.debug(f"数据源 {source_ip}.{source_table} 中没有需要校验的地址") return None # 返回结果记录 return ( source_ip, source_table, overall_result, created_at ) def clear_check_table(): """清空地址校验结果表(使用连接池)""" conn = None try: conn = get_db_connection(TARGET_CONFIG, 'sqlserver') cursor = conn.cursor() truncate_sql = f"DELETE FROM {CHECK_RESULT_TABLE} WHERE TABLE_NAME !='line1assembly'" cursor.execute(truncate_sql) conn.commit() logger.info(f"已清空地址校验结果表 {CHECK_RESULT_TABLE}") return True except Exception as e: logger.error(f"清空结果表失败: {str(e)}") return False finally: if conn: release_db_connection(conn, TARGET_CONFIG, 'sqlserver') def ensure_check_table(): """确保地址校验结果表存在(使用连接池)""" conn = None try: conn = get_db_connection(TARGET_CONFIG, 'sqlserver') cursor = conn.cursor() create_table_sql = f""" IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = '{CHECK_RESULT_TABLE}') BEGIN CREATE TABLE {CHECK_RESULT_TABLE} ( id INT IDENTITY(1,1) PRIMARY KEY, host_ip VARCHAR(50) NOT NULL, -- 源主机IP table_name VARCHAR(50) NOT NULL, -- 源表名称 check_result TINYINT NOT NULL, -- 校验结果(1/0/-1) data_created_at DATETIME NOT NULL -- 数据创建时间 ); CREATE INDEX idx_host_table ON {CHECK_RESULT_TABLE} (host_ip, table_name); CREATE INDEX idx_result ON {CHECK_RESULT_TABLE} (check_result); END """ cursor.execute(create_table_sql) conn.commit() logger.info(f"地址校验结果表 {CHECK_RESULT_TABLE} 检查/创建完成") return True except Exception as e: logger.error(f"创建地址校验结果表失败: {str(e)}") return False finally: if conn: release_db_connection(conn, TARGET_CONFIG, 'sqlserver') def save_check_results(results: List[Tuple]): """保存地址校验结果到数据库(使用连接池和批量插入)""" if not results: logger.info("无校验结果需要保存") return True if not ensure_check_table(): logger.error("无法确保校验结果表存在,跳过保存") return False # 先清空结果表 if not clear_check_table(): logger.error("清空结果表失败,跳过保存") return False conn = None try: conn = get_db_connection(TARGET_CONFIG, 'sqlserver') cursor = conn.cursor() # 使用高效批量插入 params = [(ip, table, result, created_at) for ip, table, result, created_at in results] # 构建参数化批量插入语句 insert_query = f""" INSERT INTO {CHECK_RESULT_TABLE} (host_ip, table_name, check_result, data_created_at) VALUES (?, ?, ?, ?) """ # 使用executemany进行批量插入 cursor.executemany(insert_query, params) conn.commit() logger.info(f"成功保存 {len(results)} 条地址校验结果") return True except Exception as e: logger.error(f"保存校验结果失败: {str(e)}") return False finally: if conn: release_db_connection(conn, TARGET_CONFIG, 'sqlserver') def process_data_source(source: Dict, address_set: Set[str]) -> Union[Tuple, None]: """并行处理单个数据源""" try: raw_records = extract_data(source) if not raw_records: logger.debug(f"数据源 {source['table']}@{source['host']} 无新数据") return None # 只处理最新的一条记录 data, created_at = raw_records[0] return process_source_data( data, created_at, address_set, source['host_ip'], source['table'] ) except Exception as e: logger.error(f"处理数据源 {source['host']}.{source['table']} 时出错: {str(e)}") return None def run_address_check(): """执行地址校验任务(并行处理)""" start_time = time.time() logger.info("▶▶▶ 开始地址校验任务 ◀◀◀") try: # 获取需要校验的地址集合 address_set = get_address_set(TARGET_CONFIG) if not address_set: logger.warning("未获取到需要校验的地址集合,任务终止") return False # 使用线程池并行处理数据源 all_check_results = [] # 根据CPU核心数确定线程数 max_workers = min(len(DATA_SOURCES), 4 * (os.cpu_count() or 1)) with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: # 提交所有任务 future_to_source = {executor.submit(process_data_source, source, address_set): source for source in DATA_SOURCES} # 收集结果 for future in concurrent.futures.as_completed(future_to_source): source = future_to_source[future] try: result = future.result() if result: all_check_results.append(result) except Exception as e: logger.error(f"处理数据源 {source['host']}.{source['table']} 时出错: {str(e)}") # 保存校验结果 if all_check_results: logger.info(f"准备保存 {len(all_check_results)} 条地址校验结果") save_success = save_check_results(all_check_results) else: logger.info("无有效的地址校验结果需要保存") save_success = True elapsed = time.time() - start_time logger.info(f"▶▶▶ 地址校验任务完成,耗时 {elapsed:.2f} 秒 ◀◀◀") return save_success except Exception as e: logger.exception(f"地址校验任务严重错误: {str(e)}") return False def cleanup_connection_pools(): """清理所有连接池资源""" logger.info("清理连接池资源...") # 清理PostgreSQL连接池 for host, pool in postgres_pools.items(): if pool: logger.info(f"清理PostgreSQL连接池: {host}") while not pool.pool.empty(): try: conn = pool.pool.get_nowait() conn.close() except: pass # 清理SQL Server连接池 if sqlserver_pool: logger.info("清理SQL Server连接池") while not sqlserver_pool.pool.empty(): try: conn = sqlserver_pool.pool.get_nowait() conn.close() except: pass def run_scheduler(): """定时任务调度(每分钟运行一次)""" logger.info("启动定时调度器,每分钟执行一次地址校验") # 初始化连接池 init_connection_pools() # 初始执行 run_address_check() # 定时任务 schedule.every(1).minutes.do(run_address_check) try: while True: try: schedule.run_pending() time.sleep(1) except KeyboardInterrupt: logger.info("用户中断,退出程序") break except Exception as e: logger.error(f"调度器错误: {str(e)}") time.sleep(60) # 出错后休眠1分钟 finally: # 清理连接池资源 cleanup_connection_pools() if __name__ == "__main__": run_scheduler() 一个地址对应多个位索引,应该是返回多条数据,但是结果只返回一个地址的数据。
最新发布
12-02
import re import psycopg2 import pyodbc from datetime import datetime # 配置信息 TABLE_NAMES = [ "line1block", "line1cam", "line1crank", "line1head", "line1hsg", "line2block", "line2cam", "line2crank", "line2head" ] TARGET_CODES = [ "GY100", "GY101", "GY102", "GY103", "GY104", "GY105", "GY106", "GY107", "GY108", "GY109", "GY10A", "GY10B", "GY10C", "GY10D", "GY10E", "GY116", "GY11F", "GY120", "GY121", "GY122", "GY124", "GY126", "GY128", "GY130", "GY131", "GY132", "GY133" ] # PostgreSQL 数据源配置 DATA_SOURCES = [] for table_name in TABLE_NAMES: DATA_SOURCES.append({ 'host': '192.168.154.11', 'port': '5432', 'database': 'andondata', 'user': 'powertrain', 'password': 'andromeda', 'table': table_name }) DATA_SOURCES.append({ 'host': '192.168.151.11', 'port': '5432', 'database': 'andondata', 'user': 'powertrain', 'password': 'andromeda', 'table': table_name }) # SQL Server 配置 SQL_SERVER_CONFIG = { 'server': '192.168.10.116', 'database': '现场DB', 'user': 'sa', 'password': 'gtec_6600', 'table': 'check_results' } def parse_data_string(data_str): """精确解析数据格式 {{GY100,0000010100000101},{GY101,0000010100000101}}""" parsed_data = {} # 处理空值 if not data_str or not isinstance(data_str, str): return parsed_data # 精确匹配格式:{{code,bin_str},{code,bin_str}} pattern = r'\{\s*([A-Z0-9]+)\s*,\s*([01]{16})\s*\}' matches = re.findall(pattern, data_str) for match in matches: code = match[0].strip().upper() binary_str = match[1].strip() # 确保是16位二进制字符串 if len(binary_str) == 16 and all(c in '01' for c in binary_str): parsed_data[code] = binary_str return parsed_data def check_condition(parsed_data): """检查所有存在的目标编码是否满足第8位(索引7)和第16位(索引15)同时为1""" if not parsed_data: return 0, "No data found" existing_codes = [code for code in TARGET_CODES if code in parsed_data] if not existing_codes: return 0, "No target codes found" all_satisfied = True error_details = [] for code in existing_codes: binary_str = parsed_data[code] # 验证长度 if len(binary_str) != 16: all_satisfied = False error_details.append(f"{code}: Invalid length {len(binary_str)}") continue # 检查第8位(索引7)和第16位(索引15) bit8 = binary_str[7] bit16 = binary_str[15] if bit8 != '1' or bit16 != '1': all_satisfied = False error_details.append(f"{code}: Bit8={bit8}, Bit16={bit16} | {binary_str}") if all_satisfied: return 1, "All codes satisfy condition" else: return 0, "; ".join(error_details) def main(): # 测试数据 test_data = "{{GY100,0000010100000101},{GY101,0000010100000101},{GY102,00000011000000001}}" parsed = parse_data_string(test_data) print(f"Test parse: {parsed}") result, details = check_condition(parsed) print(f"Test result: {result}, Details: {details}") # SQL Server连接 try: sql_conn = pyodbc.connect( f"DRIVER={{ODBC Driver 17 for SQL Server}};" f"SERVER={SQL_SERVER_CONFIG['server']};" f"DATABASE={SQL_SERVER_CONFIG['database']};" f"UID={SQL_SERVER_CONFIG['user']};" f"PWD={SQL_SERVER_CONFIG['password']}" ) sql_cursor = sql_conn.cursor() # 创建结果表(如果不存在) sql_cursor.execute(""" IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'check_results') CREATE TABLE check_results ( id INT IDENTITY(1,1) PRIMARY KEY, host VARCHAR(50) NOT NULL, table_name VARCHAR(50) NOT NULL, result TINYINT NOT NULL, createAt DATETIME NOT NULL, check_time DATETIME NOT NULL, details NVARCHAR(MAX) NULL ) """) sql_conn.commit() except Exception as e: print(f"SQL Server connection failed: {str(e)}") return # 处理所有数据源 for source in DATA_SOURCES: host = source['host'] table_name = source['table'] try: # PostgreSQL连接 pg_conn = psycopg2.connect( host=host, port=source['port'], database=source['database'], user=source['user'], password=source['password'] ) cursor = pg_conn.cursor() # 获取最新记录 query = f""" SELECT data, "createdAt" FROM {table_name} ORDER BY "createdAt" DESC LIMIT 1 """ cursor.execute(query) row = cursor.fetchone() if row: data_str = row[0] print (f"Data from {table_name}: {data_str}") create_at = row[1] # 解析数据 parsed_data = parse_data_string(data_str) print(f"Parsed data from {host}/{table_name}: {parsed_data}") # 检查条件 result, details = check_condition(parsed_data) # 存储结果 sql_cursor.execute( "INSERT INTO check_results (host, table_name, result, createAt, check_time, details) " "VALUES (?, ?, ?, ?, ?, ?)", host, table_name, result, create_at, datetime.now(), details ) sql_conn.commit() print(f"[SUCCESS] {host}/{table_name}: Result={result}, Details={details}") else: # 无记录处理 sql_cursor.execute( "INSERT INTO check_results (host, table_name, result, createAt, check_time, details) " "VALUES (?, ?, ?, ?, ?, ?)", host, table_name, 0, datetime.now(), datetime.now(), "No records found" ) sql_conn.commit() print(f"[WARNING] {host}/{table_name}: No records found") cursor.close() pg_conn.close() except Exception as e: error_msg = f"Processing {host}/{table_name} failed: {str(e)}" print(f"[ERROR] {error_msg}") try: sql_cursor.execute( "INSERT INTO check_results (host, table_name, result, createAt, check_time, details) " "VALUES (?, ?, ?, ?, ?, ?)", host, table_name, -1, datetime.now(), datetime.now(), error_msg ) sql_conn.commit() except Exception as inner_e: print(f"[CRITICAL] Failed to log error: {inner_e}") sql_cursor.close() sql_conn.close() if __name__ == "__main__": main() print (f"Data from {table_name}: {data_str}")输出完整的数据,print(f"Parsed data from {host}/{table_name}: {parsed_data}")则输出Parsed data from 192.168.151.11/line2cam: {}
11-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值