MySQL去重3种方法​,还有谁不会?

本文探讨了MySQL和窗口函数SQL(如HiveSQL、Oracle)中如何使用distinct、group by和row_number去重功能,通过实例展示了在计算任务总数时的不同方法,并对比了distinct与group by的效率和使用场景。同时,还提供了distinct与group by在实际操作中的例子和测试表Test的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大家好,我是乔戈里。

在使用SQL提数的时候,常会遇到表内有重复值的时候,比如我们想得到 uv (独立访客),就需要做去重。

在 MySQL 中通常是使用 distinct 或 group by子句,但在支持窗口函数的 sql(如Hive SQL、Oracle等等) 中还可以使用 row_number 窗口函数进行去重。

举个栗子,现有这样一张表 task:

384c39ecd59d9b3f6565849075f24063.png

备注:

  • task_id: 任务id;

  • order_id: 订单id;

  • start_time: 开始时间

注意:一个任务对应多条订单

我们需要求出任务的总数量,因为 task_id 并非唯一的,所以需要去重:

distinct

-- 列出 task_id 的所有唯一值(去重后的记录)
-- select distinct task_id
-- from Task;

-- 任务总数
select count(distinct task_id) task_num
from Task;

distinct 通常效率较低。它不适合用来展示去重后具体的值,一般与 count 配合用来计算条数。

distinct 使用中,放在 select 后边,对后面所有的字段的值统一进行去重。比如distinct后面有两个字段,那么 1,1 和 1,2 这两条记录不是重复值 。

group by

-- 列出 task_id 的所有唯一值(去重后的记录,null也是值)
-- select task_id
-- from Task
-- group by task_id;

-- 任务总数
select count(task_id) task_num
from (select task_id
      from Task
      group by task_id) tmp;

row_number

row_number 是窗口函数,语法如下:

row_number() over (partition by <用于分组的字段名> order by <用于组内排序的字段名>)

其中 partition by 部分可省略。

-- 在支持窗口函数的 sql 中使用
select count(case when rn=1 then task_id else null end) task_num
from (select task_id
       , row_number() over (partition by task_id order by start_time) rn
   from Task) tmp;

此外,再借助一个表 test 来理理 distinct 和 group by 在去重中的使用:

ba7ac682477f8e12a676da6c33631262.png

-- 下方的分号;用来分隔行
select distinct user_id
from Test;    -- 返回 1; 2

select distinct user_id, user_type
from Test;    -- 返回1, 1; 1, 2; 2, 1

select user_id
from Test
group by user_id;    -- 返回1;  2

select user_id, user_type
from Test
group by user_id, user_type;    -- 返回1, 1; 1, 2; 2, 1

select user_id, user_type
from Test
group by user_id;
-- Hive、Oracle等会报错,mysql可以这样写。
-- 返回1, 1 或 1, 2 ; 2, 1(共两行)。只会对group by后面的字段去重,就是说最后返回的记录数等于上一段sql的记录数,即2条
-- 没有放在group by 后面但是在select中放了的字段,只会返回一条记录(好像通常是第一条,应该是没有规律的)

原文链接:blog.youkuaiyun.com/xienan_ds_zj/article/details/103869048

近期技术热文

往期推荐

/** * @notes 菜鸟退货入仓费明细核对逻辑(优化版) * @param y e a r M o n t h ∗ @ r e t u r n b o o l ∗ @ t h r o w s D a t a N o t F o u n d E x c e p t i o n ∗ @ t h r o w s D b E x c e p t i o n ∗ @ t h r o w s M o d e l N o t F o u n d E x c e p t i o n ∗ @ a u t h o r 胡军 ∗ @ d a t e 2025 / 06 / 26 ∗ / p u b l i c f u n c t i o n c o m p u t e R e t u r n I t e m V e r i f y D o ( yearMonth∗@returnbool∗@throwsDataNotFoundException∗@throwsDbException∗@throwsModelNotFoundException∗@author胡军∗@date2025/06/26∗/publicfunctioncomputeReturnItemVerifyDo( yearMonth): bool { // 获取指定月份的时间范围(月初到月末) m o n t h T i m e R a n g e = monthTimeRange= this->getMonthTimeRange( y e a r M o n t h ) ; / / 预加载并缓存报价数据,使用键值对存储(仓库名 = > 报价信息) / / 避免在后续循环中复查询数据库,提高性能 yearMonth);//预加载并缓存报价数据,使用键值对存储(仓库名=>报价信息)//避免在后续循环中复查询数据库,提高性能 warehouseQuotes = []; w a r e h o u s e L i s t = C o m p u t e R e t u r n I t e m i z a t i o n M o d e l : : w h e r e B e t w e e n ( ′ b u s i n e s s t i m e ′ , [ warehouseList=ComputeReturnItemizationModel::whereBetween( ′ business t ​ ime ′ ,[ monthTimeRange[‘startTime’], m o n t h T i m e R a n g e [ ′ e n d T i m e ′ ] ] ) − > g r o u p ( ′ w a r e h o u s e n a m e ′ ) − > c o l u m n ( ′ w a r e h o u s e n a m e ′ ) ; / / 批量获取所有仓库的首件和每增加一件报价记录 ( 同一个仓库报价必须是两条并且首件报价在前每增加一件报价在后否则计算错误 ) f o r e a c h ( monthTimeRange[ ′ endTime ′ ]])−>group( ′ warehouse n ​ ame ′ )−>column( ′ warehouse n ​ ame ′ );//批量获取所有仓库的首件和每增加一件报价记录(同一个仓库报价必须是两条并且首件报价在前每增加一件报价在后否则计算错误)foreach( warehouseList as ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: …记录 firstResult = ComputeReturnFeeQuoteModel::where(‘warehouse’, w a r e h o u s e ) − > o r d e r ( ′ i d a s c ′ ) − > f i n d ( ) ; warehouse)−>order( ′ idasc ′ )−>find(); firstOrderQuote = f i r s t R e s u l t ? firstResult? firstResult->toArray() : []; // 获取该仓库的每增加一件报价记录 l a s t R e s u l t = C o m p u t e R e t u r n F e e Q u o t e M o d e l : : w h e r e ( ′ w a r e h o u s e ′ , lastResult=ComputeReturnFeeQuoteModel::where( ′ warehouse ′ , warehouse)->order(‘id desc’)->find(); l a s t O r d e r Q u o t e = lastOrderQuote= lastResult ? l a s t R e s u l t − > t o A r r a y ( ) : [ ] ; / / 仅当首件和续件报价都存在时才保存(确保数据完整性) i f ( ! e m p t y ( lastResult−>toArray():[];//仅当首件和续件报价都存在时才保存(确保数据完整性)if(!empty( firstOrderQuote) && !empty(ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … warehouseQuotes[ w a r e h o u s e ] = [ ′ f i r s t ′ = > warehouse]=[ ′ first ′ => firstOrderQuote, // 首件价格信息 ‘last’ => ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 61: …]; }̲ } … status = true; // 处理状态标识 b a t c h S i z e = 500 ; / / 批次大小即每次读取的数据条数 batchSize=500;//批次大小即每次读取的数据条数 reconnectInterval = 200; // 每10万条新连接一次数据库(200批次=10万条) u p d a t e C o u n t = 0 ; / / 记录已更新的总记录数 updateCount=0;//记录已更新的总记录数 batchCount = 0; // 记录当前批次数 try { // 使用游标分批处理数据,每次只加载少量数据到内存 // 避免一次性加载大量数据导致内存溢出 q u e r y = C o m p u t e R e t u r n I t e m i z a t i o n M o d e l : : w h e r e B e t w e e n ( ′ b u s i n e s s t i m e ′ , [ query=ComputeReturnItemizationModel::whereBetween( ′ business t ​ ime ′ ,[ monthTimeRange[‘startTime’], m o n t h T i m e R a n g e [ ′ e n d T i m e ′ ] ] ) ; monthTimeRange[ ′ endTime ′ ]]); query->chunk( b a t c h S i z e , f u n c t i o n ( batchSize,function( items) use ( &ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;&&#39; at position 51: … &̲ updateCount, // 引用传递更新计数 & b a t c h C o u n t , / / 引用传递批次计数 batchCount,//引用传递批次计数 warehouseQuotes, // 仓库报价数据 r e c o n n e c t I n t e r v a l , / / 连间隔 reconnectInterval,//连间隔 yearMonth ) { b a t c h C o u n t + + ; batchCount++; updateBuffer = []; // 批量更新缓冲区,存储待更新的数据 // 遍历当前批次的所有明细记录 foreach ( i t e m s a s itemsas item) { w a r e h o u s e N a m e = warehouseName= item->warehouse_name; i t e m D a t a = itemData= item->toArray(); t h e o r e t i c a l F e e = 0 ; / / 检查仓库是否有对应的报价数据 i f ( i s s e t ( theoreticalFee=0;//检查仓库是否有对应的报价数据if(isset( warehouseQuotes[ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … quoteData = w a r e h o u s e Q u o t e s [ warehouseQuotes[ warehouseName]; // 将CN订单SKU总量(克)转换为千克 b u b b l e V o l u m e K g = bubbleVolumeKg= itemData[‘bubble_volume_1kg’] / 1000; q u a n t i t y = quantity= itemData[‘total_goods_quantity’]; // 确定价格类型 p r i c e T y p e = priceType= bubbleVolumeKg <= 0.5 ? ‘tiny’ : ( b u b b l e V o l u m e K g < = 3 ? ′ s m a l l ′ : ( bubbleVolumeKg<=3? ′ small ′ :( bubbleVolumeKg <= 5 ? ‘medium’ : ( b u b b l e V o l u m e K g < = 10 ? ′ l a r g e ′ : ′ t e n ′ ) ) ) ; / / 计算费用 bubbleVolumeKg<=10? ′ large ′ : ′ ten ′ )));//计算费用 theoreticalFee += ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: …irst&#39;]["price_{ priceType}"]; if (ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … theoreticalFee += ( q u a n t i t y − 1 ) ∗ quantity−1)∗ quoteData[‘last’]["price_{ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 11: priceType}̲"]; … yearMonth . “的订单明细核对匹配不到退货入仓费报价表la_compute_return_fee_quote当中的仓库名称,明细数据id为” . i t e m D a t a [ ′ i d ′ ] ) ; / / 未匹配时设置为 n u l l 以便标识 itemData[ ′ id ′ ]);//未匹配时设置为null以便标识 theoreticalFee = null; } // 准备更新数据,存入缓冲区 u p d a t e B u f f e r [ updateBuffer[ itemData[‘id’]] = [ ‘theoretical_fee’ => t h e o r e t i c a l F e e , / / 理论费 用 ′ f e e d i f f e r e n c e ′ = > theoreticalFee,//理论费用 ′ fee d ​ ifference ′ => itemData[‘billing_amount’] - (ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 71: … }̲ … this->batchUpdate(‘la_compute_return_fee’, u p d a t e B u f f e r , [ ′ t h e o r e t i c a l f e e ′ , ′ f e e d i f f e r e n c e ′ ] ) ; updateBuffer,[ ′ theoretical f ​ ee ′ , ′ fee d ​ ifference ′ ]); updateCount += count( u p d a t e B u f f e r ) ; / / 更新总计数 / / 定期数据库,避免长时间运行导致连接断开 i f ( updateBuffer);//更新总计数//定期数据库,避免长时间运行导致连接断开if( batchCount % ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … this->reconnectDatabase(); Log::info(“菜鸟退货入仓费用核对已处理 {ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 13: updateCount}̲ 条,进行数据库连"); … items, ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 29: …); }̲); } ca… e) { // 记录异常信息,确保错误可追溯(保留原始注释逻辑) Log::error(‘【菜鸟退货入仓费明细核对异常】–月份为:’ . y e a r M o n t h . " 的费用核对发生错误 : " . yearMonth."的费用核对发生错误:". e->getMessage()); ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 37: …标记处理失败 }̲ // 记录处… updateCount} 条记录”); return $ status; } /** * 高效批量更新方法(单SQL更新多条) * @param string $ table 表名 * @param array $ data 更新数据,格式:[id => [&#39;field1&#39; => &#39;value1&#39;, &#39;field2&#39; => &#39;value2&#39;]] * @param array $ fields 需要更新的字段 */ private function batchUpdate(string $ table, array $ data, array $ fields) { // 数据为空时直接返回,避免无效操作 if (empty($ data) || empty($ fields)) return; $ cases = []; // 存储CASE WHEN语句的数组 $ ids = []; // 存储所有需要更新的ID $ params = []; // 存储预处理语句的参数 // 构建CASE WHEN更新语句(每个字段一个CASE WHEN) foreach ($ fields as $ field) { $ cases[$ field] = &#39;CASE id &#39;; // 为每个ID和对应字段值构建WHEN子句 foreach ($ data as $ id => $ row) { $ cases[$ field] .= "WHEN {$ id} THEN ? "; // 占位符用于预处理语句 $ params[] = $ row[$ field]; // 对应的值 $ ids[] = $ id; // 记录ID } $ cases[$ field] .= &#39;END&#39;; // 结束CASE语句 } // 并拼接ID列表 $ idsStr = implode(&#39;,&#39;, array_unique($ ids)); // 构建SET子句(每个字段的CASE WHEN语句) $ setClauses = []; foreach ($ fields as $ field) { $ setClauses[] = "{$ field} = {$ cases[$ field]}"; } // 构建完整的UPDATE SQL语句(保留SQL案例注释) /* 最后的执行sql可以视为(案例sql): UPDATE la_reverse_delivery_fee SET theoretical_amount = CASE id WHEN 1001 THEN 100 -- 当ID=1001时,更新为100 WHEN 1002 THEN 200 -- 当ID=1002时,更新为200 END, fee_difference = CASE id WHEN 1001 THEN 5 -- 当ID=1001时,更新为5 WHEN 1002 THEN 10 -- 当ID=1002时,更新为10 END WHERE id IN (1001,1002); 其实就是巧妙地利用了 SQL 的CASE WHEN语法,将多行更新合并为单条 SQL,是一种常见的数据库优化技巧! */ $ sql = "UPDATE {$ table} SET " . implode(&#39;, &#39;, $ setClauses) . " WHERE id IN ({$ idsStr})"; // 执行预处理语句,提高安全性和性能 Db::execute($ sql, $ params); } // 数据库方法,用于长时间运行的任务,避免连接超时 private function reconnectDatabase() { try { $ connection = \think\facade\Db::connect(); $ connection->close(); // 关闭当前连接 $ connection->connect(); // 新建立连接 } catch (\Exception $ e) { // 记录连失败日志,但不中断程序执行 Log::error(&#39;【菜鸟退货入仓费用核对数据库连失败】&#39; . $ e->getMessage()); } } /** * @notes 根据年月比如2025-05获取当月时间范围 精确到秒 * @param string y e a r M o n t h ∗ @ r e t u r n a r r a y ∗ @ a u t h o r 胡军 ∗ @ d a t e 2025 / 06 / 23 ∗ / p r i v a t e f u n c t i o n g e t M o n t h T i m e R a n g e ( s t r i n g yearMonth∗@returnarray∗@author胡军∗@date2025/06/23∗/privatefunctiongetMonthTimeRange(string yearMonth): array { // 验证输入格式 (YYYY-MM) if (!preg_match(‘/^\d{4}-(0[1-9]|1[0-2]) / ′ , / ′ , yearMonth)) { throw new InvalidArgumentException(‘输入格式不正确,必须为YYYY-MM格式’); } list( y e a r , year, month) = explode(’-&#39;, y e a r M o n t h ) ; / / 构建开始时间 yearMonth);//构建开始时间 startTime = “{ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 6: year}̲-{ month}-01 00:00:00”; // 使用DateTime类计算当月最后一天 ParseError: KaTeX parse error: Undefined control sequence: \DateTime at position 17: …lastDay = (new \̲D̲a̲t̲e̲T̲i̲m̲e̲("{ year}-{ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 7: month}̲-01")) … endTime = "{ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 6: year}̲-{ month}-{ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 9: lastDay}̲ 23:59:59"; … startTime, ‘endTime’ => $ endTime ]; } 这是我之前的业务模块处理100万数据核对的代码,也是您给出的方案,那么我上次提问的代码: /** * @notes 京东仓储服务费核对逻辑 * @param y e a r M o n t h ∗ @ r e t u r n b o o l ∗ @ t h r o w s D a t a N o t F o u n d E x c e p t i o n ∗ @ t h r o w s D b E x c e p t i o n ∗ @ t h r o w s M o d e l N o t F o u n d E x c e p t i o n ∗ @ a u t h o r 胡军 ∗ @ d a t e 2025 / 06 / 27 ∗ / p u b l i c f u n c t i o n w a r e H o u s i n g F e e V e r i f y D o ( yearMonth∗@returnbool∗@throwsDataNotFoundException∗@throwsDbException∗@throwsModelNotFoundException∗@author胡军∗@date2025/06/27∗/publicfunctionwareHousingFeeVerifyDo( yearMonth):bool{ m o n t h T i m e R a n g e = monthTimeRange= this->getMonthTimeRange( y e a r M o n t h ) ; / / 获取时间范围内的数据并进行分组统计 / / t o t a l q u a n t i t y 总数 / / t o t a l s e t t l e m e n t a m o u n t 总的结算金额 yearMonth);//获取时间范围内的数据并进行分组统计//total q ​ uantity总数//total s ​ ettlement a ​ mount总的结算金额 itemizationMonthList = WareHousingFeesItemizationModel::whereBetween(‘business_time’, [ m o n t h T i m e R a n g e [ ′ s t a r t T i m e ′ ] , monthTimeRange[ ′ startTime ′ ], monthTimeRange[‘endTime’]]) ->field([ ‘document_number’, ‘document_type’, ‘SUM(quantity) as total_quantity’, ‘SUM(settlement_amount) as total_settlement_amount’ ]) ->group(‘document_number, document_type’) ->select() ->toArray(); //一次性读取报价单避免foreach循环 提升效率 q u o t e L i s t = W a r e H o u s i n g F e e s Q u o t e M o d e l : : s e l e c t ( ) − > t o A r r a y ( ) ; quoteList=WareHousingFeesQuoteModel::select()−>toArray(); quoteListRst = []; foreach ( q u o t e L i s t a s quoteListas item) { q u o t e L i s t R s t [ quoteListRst[ item[‘service_type’]] = ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 16: item; }̲ if(!em… quoteListRst)){ foreach( i t e m i z a t i o n M o n t h L i s t a s itemizationMonthListas key => ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … itemizationMonthList[ k e y ] [ ′ t h e o r e t i c a l a m o u n t ′ ] = 0 ; i f ( key][ ′ theoretical a ​ mount ′ ]=0;if( value[‘document_type’] == ‘出库单’ && !empty(ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … // value[‘total_quantity’] 数量 if(ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … itemizationMonthList[ k e y ] [ ′ t h e o r e t i c a l a m o u n t ′ ] = key][ ′ theoretical a ​ mount ′ ]= quoteListRst[‘出库单’][‘first_three_items’]; } else { i t e m i z a t i o n M o n t h L i s t [ itemizationMonthList[ key][‘theoretical_amount’] = q u o t e L i s t R s t [ ′ 出库 单 ′ ] [ ′ f i r s t t h r e e i t e m s ′ ] + ( quoteListRst[ ′ 出库单 ′ ][ ′ first t ​ hree i ​ tems ′ ]+( value[‘total_quantity’] - 3) * ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 63: … }̲ … value[‘document_type’] == ‘退供单’ && !empty(ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … itemizationMonthList[ k e y ] [ ′ t h e o r e t i c a l a m o u n t ′ ] = key][ ′ theoretical a ​ mount ′ ]= quoteListRst[‘退供单’][‘first_three_items’] * ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 43: … }̲ … value[‘document_type’] == ‘退货单’ && !empty(ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … if( value[‘total_quantity’] <= 3){ i t e m i z a t i o n M o n t h L i s t [ itemizationMonthList[ key][‘theoretical_amount’] = ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 64: … }̲ else { … itemizationMonthList[ k e y ] [ ′ t h e o r e t i c a l a m o u n t ′ ] = key][ ′ theoretical a ​ mount ′ ]= quoteListRst[‘退货单’][‘first_three_items’] + ( v a l u e [ ′ t o t a l q u a n t i t y ′ ] − 3 ) ∗ value[ ′ total q ​ uantity ′ ]−3)∗ quoteListRst[‘退货单’][‘additional_items’]; } } //正常计算出来的理论金额不应该是0 那么这个时候就要记录日志便于排查 if( i t e m i z a t i o n M o n t h L i s t [ itemizationMonthList[ key][‘theoretical_amount’] == 0){ //echo v a l u e [ ′ d o c u m e n t n u m b e r ′ ] . P H P E O L ; L o g : : w a r n i n g ( ′ 【京东仓储服务费明细核对】 − − 月份为 : ′ . value[ ′ document n ​ umber ′ ].PHP E ​ OL;Log::warning( ′ 【京东仓储服务费明细核对】−−月份为: ′ . yearMonth.“的京东仓储服务费订单明细核对匹配不到京东仓储服务费报价表la_storage_service_quotes当中的类型,明细单据编号为”. v a l u e [ ′ d o c u m e n t n u m b e r ′ ] ) ; u n s e t ( value[ ′ document n ​ umber ′ ]);unset( itemizationMonthList[ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 55: … }̲else{ … itemizationMonthList[ k e y ] [ ′ b a l a n c e ′ ] = key][ ′ balance ′ ]= value[‘total_settlement_amount’] - i t e m i z a t i o n M o n t h L i s t [ itemizationMonthList[ key][‘theoretical_amount’]; } } //批量分批次更新数据库 s t a t u s = t r u e ; status=true; batchSize = 50; // 每批10条记录 t o t a l C o u n t = c o u n t ( totalCount=count( itemizationMonthList); b a t c h C o u n t = c e i l ( batchCount=ceil( totalCount / b a t c h S i z e ) ; batchSize); itemizationModel = new WareHousingFeesItemVeryModel(); for ( i = 0 ; i=0; i < b a t c h C o u n t ; batchCount; i++) { b a t c h D a t a = a r r a y s l i c e ( batchData=array s ​ lice( itemizationMonthList, i ∗ i∗ batchSize, b a t c h S i z e ) ; batchSize); documentNumbers = array_column(ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … itemizationModel->startTrans(); // 批量删除操作(根据单据号) if (!empty(ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … itemizationModel->whereIn(‘document_number’, ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 50: … }̲ … itemizationModel->saveAll( b a t c h D a t a ) ; batchData); itemizationModel->commit(); } catch (\Exception ParseError: KaTeX parse error: Expected &#39;}&#39;, got &#39;EOF&#39; at end of input: … itemizationModel->rollback(); //记录日志 Log::error(‘【京东仓储服务费明细核对异常】–月份为:’. y e a r M o n t h . " 的费用核对发生错误 : " . yearMonth."的费用核对发生错误:". e->getMessage()); //其中一个批次数据处理失败则直接退出循环 不再继续执行后续批次的数据处理 报错给前端显示 ParseError: KaTeX parse error: Expected &#39;EOF&#39;, got &#39;}&#39; at position 61: … }̲ } … status; }else{ return false; } } /** * @notes 根据年月比如2025-05获取当月时间范围 精确到秒 (git有问题未解决 暂时无法写入common.php当中 临时放这) * @param string $ yearMonth * @return array * @author 胡军 * @date 2025/06/27 */ private function getMonthTimeRange(string $ yearMonth): array { // 验证输入格式 (YYYY-MM) if (!preg_match(&#39;/^\d{4}-(0[1-9]|1[0-2])$/&#39;, $ yearMonth)) { throw new InvalidArgumentException(&#39;输入格式不正确,必须为YYYY-MM格式&#39;); } list($ year, $ month) = explode(&#39;-&#39;, $ yearMonth); // 构建开始时间 $ startTime = "{$ year}-{$ month}-01 00:00:00"; // 使用DateTime类计算当月最后一天 $ lastDay = (new \DateTime("{$ year}-{$ month}-01")) ->modify(&#39;last day of this month&#39;) ->format(&#39;d&#39;); // 构建结束时间 $ endTime = "{$ year}-{$ month}-{$ lastDay} 23:59:59"; return [ &#39;startTime&#39; => $ startTime, &#39;endTime&#39; => $ endTime ]; } 是不是也可以按照这种优化思路改造呢?
最新发布
07-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值