<think>我们之前构建的存储过程使用了REPEAT函数来重复生成多个值,但是REPEAT函数返回的是字符串重复多次的结果,然而在构建INSERT语句时,我们需要的是多个值列表,每个值列表之间用逗号分隔。但是REPEAT函数只是简单地将字符串重复,并没有在重复的字符串之间添加逗号,因此会导致生成的SQL语句中,多个值列表之间没有逗号分隔,从而造成语法错误。
例如,我们想要生成:
('val1',...), ('val1',...), ...
但是使用REPEAT后,会变成:
('val1',...)('val1',...)...
所以我们需要在每次重复之间添加逗号,但是注意最后一个值后面不能有逗号。
因此,我们需要调整策略,不能直接用REPEAT,而是通过循环构建一个长字符串,在每次循环中添加一个值,并在每个值之间添加逗号(除了最后一个)。
但是,在存储过程中,我们可以使用WHILE循环来构建一个包含多个值的字符串,每个值之间用逗号分隔。然而,在存储过程中直接构建一个包含1000个值的字符串可能会超出SQL语句的最大长度(尤其是当每个值字符串很长时)。因此,我们需要权衡。
另一种方法是使用临时表或者内存表,但这里我们继续使用动态SQL,但改进构建多个值的方式。
修改后的思路:
1. 在每一批(batch)中,我们构建一个包含多个记录值的字符串,每个记录值用括号括起来,记录之间用逗号分隔。
2. 我们可以使用一个循环(从1到当前批次要插入的数量)来拼接每个值字符串,并在每个值字符串后添加逗号(除了最后一个)。
3. 但为了避免在循环中拼接长字符串(可能会慢),我们可以使用REPEAT来生成不带逗号的多个值,然后使用字符串替换的方式在中间插入逗号?但是这样并不直观。
更直接的方法:使用一个循环来拼接当前批次的所有值字符串,并在每次循环时添加逗号(除了最后一次)。但是,在存储过程中,使用循环拼接字符串可能会比较慢,特别是当批次大小很大时(比如1000条)。不过,由于我们每批只循环1000次,这个开销是可以接受的。
因此,我们修改存储过程如下:
我们将为每一批构建一个字符串,该字符串由多个值组成,每个值之间用逗号分隔。具体步骤如下:
- 初始化一个空字符串`batch_values`。
- 循环从1到当前批次的数量(即`LEAST(remaining, batch_size)`),在每次循环中,我们添加一个值字符串,然后如果不是最后一个,就添加一个逗号。
- 然后把这个`batch_values`字符串拼接到INSERT语句中。
但是,由于我们使用的是动态SQL,并且批次大小可能达到1000,所以我们需要在存储过程中使用一个内层循环。
然而,在存储过程中使用循环拼接字符串可能会遇到性能问题(因为字符串拼接在循环中可能较慢),但考虑到1000次循环,这个开销是可以接受的。
修改后的存储过程(关键部分):
```
DECLARE j INT DEFAULT 1;
DECLARE batch_values TEXT DEFAULT '';
SET @batch_count = LEAST(remaining, batch_size);
-- 构建当前批次的值列表
WHILE j <= @batch_count DO
SET batch_values = CONCAT(batch_values,
"('2025-12-10 14:30:00', 'ZT20250710001', '荆州中通云仓', '湖北省', 'TEST-AUX-001', ",
"'荆州市', '沙市区', '荆州-中通云仓唯品自营专用顺丰', 20, 3000.000, ",
"1.200, NULL, NULL, 5.000, NULL, '淘宝海外新加坡补发1', 'JY20250501011664', ",
"'唯品自营旗舰店', 3, 0.000, 25.500, 50.800, '9号', 2, NULL, NULL, NULL, ",
"NULL, NULL, 5.200, NULL, NULL, '3<x<=5', NULL, NULL, 30.000, 8.000, 20.800, 1)");
IF j < @batch_count THEN
SET batch_values = CONCAT(batch_values, ',');
END IF;
SET j = j + 1;
END WHILE;
```
然后,将`batch_values`拼接到INSERT语句中。
但是,注意:在存储过程中,如果使用WHILE循环嵌套,我们需要重新声明变量。另外,由于我们已经在外部有一个WHILE循环,所以内层循环需要小心作用域问题(在存储过程中,内部声明的变量只在当前BEGIN...END块中有效)。
然而,我们也可以不使用内层循环,而是通过一个技巧:使用数字辅助表,但这里我们选择内层循环。
由于存储过程不允许在同一个块中重复声明变量,我们需要在内部使用一个新的BEGIN...END块,或者使用不同的变量名。
我们重新设计存储过程,使用两个循环(外层循环控制批次,内层循环控制当前批次内的记录拼接)。
但是,考虑到性能,拼接1000条记录的内层循环不会太慢,所以可以接受。
修改后的完整存储过程如下:</think>您遇到的错误是由于存储过程中动态构建 SQL 语句时值列表之间缺少逗号分隔符导致的。我将提供一个修复后的存储过程,并解释问题原因:
### 问题分析
原存储过程使用 `REPEAT()` 函数生成多个值,但没有在值之间添加必要的逗号分隔符,导致生成的 SQL 语句如:
```sql
INSERT ... VALUES
('val1')('val2')('val3') -- 缺少逗号分隔符
```
正确格式应为:
```sql
INSERT ... VALUES
('val1'), -- 注意这里的逗号
('val2'),
('val3')
```
### 修复后的存储过程
```sql
DELIMITER //
CREATE PROCEDURE InsertMassData(IN total_rows INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE batch_size INT DEFAULT 1000;
DECLARE batch_count INT;
DECLARE remaining INT DEFAULT total_rows;
DECLARE values_list TEXT;
-- 单条记录的固定值模板
SET @single_value = CONCAT(
"('2025-12-10 14:30:00', 'ZT20250710001', '荆州中通云仓', '湖北省', 'TEST-AUX-001', ",
"'荆州市', '沙市区', '荆州-中通云仓唯品自营专用顺丰', 20, 3000.000, ",
"1.200, NULL, NULL, 5.000, NULL, '淘宝海外新加坡补发1', 'JY20250501011664', ",
"'唯品自营旗舰店', 3, 0.000, 25.500, 50.800, '9号', 2, NULL, NULL, NULL, ",
"NULL, NULL, 5.200, NULL, NULL, '3<x<=5', NULL, NULL, 30.000, 8.000, 20.800, 1)"
);
SET autocommit = 0;
WHILE remaining > 0 DO
START TRANSACTION;
-- 计算本次插入的数量
SET @current_batch = LEAST(remaining, batch_size);
SET values_list = '';
-- 构建逗号分隔的值列表
SET @counter = 1;
WHILE @counter <= @current_batch DO
SET values_list = CONCAT(values_list, @single_value);
IF @counter < @current_batch THEN
SET values_list = CONCAT(values_list, ',');
END IF;
SET @counter = @counter + 1;
END WHILE;
-- 构建完整SQL
SET @insert_sql = CONCAT(
'INSERT INTO `kerespets_admin`.`la_zhongtong_details` (',
'shipping_time, logistics_no, warehouse, province, auxiliary_column, ',
'city, region, logistics_company, total_goods_count, weight, ',
'theoretical_material_weight, theoretical_weight, material_weight, ',
'billing_weight, goods_weight_diff, goods_summary, sales_channel, ',
'shop_name, additional_pieces, beijing_shanghai_surcharge, express_fee, ',
'total_amount, model, card_quantity, goods_quantity, additional_quantity, ',
'operation_fee, theoretical_material, material_consistent, material_fee, ',
'theoretical_material_fee, billing_weight_calc, weight_range, ',
'theoretical_express_fee, beijing_shanghai_theoretical_surcharge, ',
'theoretical_total_freight, shunfeng_service_fee, difference, status',
') VALUES ', values_list
);
-- 执行插入
PREPARE stmt FROM @insert_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 更新计数器
SET remaining = remaining - @current_batch;
COMMIT;
END WHILE;
SET autocommit = 1;
END //
DELIMITER ;
```
### 关键修复点:
1. **逗号分隔符处理**:
- 使用嵌套循环构建值列表
- 在每条记录后添加逗号(除了最后一条)
- 通过 `IF @counter < @current_batch` 判断是否添加逗号
2. **性能优化**:
- 预先定义单条记录模板 `@single_value`
- 使用内存变量拼接,减少重复计算
- 保持事务分批提交机制
3. **SQL构建改进**:
- 明确分隔字段列表和值列表
- 使用 `TEXT` 类型存储长字符串
- 更清晰的变量命名
### 调用示例:
```sql
-- 测试插入10条
CALL InsertMassData(10);
-- 插入100万条
CALL InsertMassData(1000000);
```
### 注意事项:
1. 执行百万级插入前,建议先备份数据
2. 确保 `id` 字段设置为自增主键
3. 根据服务器性能调整 `batch_size`(500-5000之间)
4. 监控服务器内存使用情况