我有这张表,其中通过在
VALUE
列中拆分并按GROUPING_ID
分组来保存长字符串:
CREATE TABLE input_table
(
CHUNK_ID BIGINT NOT NULL
PRIMARY KEY,
VALUE VARCHAR(5000) NULL,
GROUPING_ID BIGINT NULL
);
我想将
VALUE
列的大小从 VARCHAR(5000)
调整为 VARCHAR(4000)
。
Values 按
GROUPING_ID
分组,因此一个 24123 个字符的字符串最初将被分成 5 行,5000 个字符中的 4 个和 4123 个字符中的 1 个。
为了减少列的大小,我需要连接分组的字符串,然后按 4000 重新拆分,因此具有 24123 个字符的字符串将保存在 7 行,4000 个字符中的 6 个和 123 个字符中的 1 个。
我想在不使用函数的情况下在 MySQL 中执行此操作。
经过一些研究,我设法连接了这些值,然后在 ChatGPT 的帮助下,我设法将连接的字符串拆分成更小的部分。
此解决方案将保持块的正确排序,并允许配置更小或更大的块大小,因此您可以使用它来减少或增加列大小。
要将
VALUE
列重新拆分为 4000,可以使用:
SET @chunk_size = 4000;
SET group_concat_max_len = @chunk_size * 50 * 2; -- chunk_size x 50 unions below x 2 bytes
START TRANSACTION;
DELETE
FROM input_table
WHERE GROUPING_ID IS NULL;
CREATE TEMPORARY TABLE temp_all_concat_input
SELECT GROUP_CONCAT(VALUE SEPARATOR '') AS CONCAT_VALUE, GROUPING_ID AS TEMP_GROUPING_ID
FROM input_table
GROUP BY GROUPING_ID;
CREATE TEMPORARY TABLE temp_re_split_input AS
SELECT SUBSTRING(CONCAT_VALUE, (@chunk_size * (seq_numbers.SEQ - 1)) + 1, @chunk_size) AS CHUNK,
concat_input.TEMP_GROUPING_ID,
seq_numbers.SEQ
FROM (SELECT 1 AS SEQ UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL
SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15 UNION ALL SELECT 16 UNION ALL
SELECT 17 UNION ALL SELECT 18 UNION ALL SELECT 19 UNION ALL SELECT 20 UNION ALL
SELECT 21 UNION ALL SELECT 22 UNION ALL SELECT 23 UNION ALL SELECT 24 UNION ALL
SELECT 25 UNION ALL SELECT 26 UNION ALL SELECT 27 UNION ALL SELECT 28 UNION ALL
SELECT 29 UNION ALL SELECT 30 UNION ALL SELECT 31 UNION ALL SELECT 32 UNION ALL
SELECT 33 UNION ALL SELECT 34 UNION ALL SELECT 35 UNION ALL SELECT 36 UNION ALL
SELECT 37 UNION ALL SELECT 38 UNION ALL SELECT 39 UNION ALL SELECT 40 UNION ALL
SELECT 41 UNION ALL SELECT 42 UNION ALL SELECT 43 UNION ALL SELECT 44 UNION ALL
SELECT 45 UNION ALL SELECT 46 UNION ALL SELECT 47 UNION ALL SELECT 48 UNION ALL
SELECT 49 UNION ALL SELECT 50) AS seq_numbers
CROSS JOIN (SELECT CONCAT_VALUE, TEMP_GROUPING_ID FROM temp_all_concat_input) AS concat_input
WHERE (@chunk_size * (seq_numbers.SEQ - 1)) + 1 <= CHAR_LENGTH(concat_input.CONCAT_VALUE)
ORDER BY concat_input.TEMP_GROUPING_ID, seq_numbers.SEQ;
TRUNCATE TABLE input_table;
INSERT INTO input_table(CHUNK_ID, VALUE, GROUPING_ID)
SELECT ROW_NUMBER() OVER (), CHUNK, TEMP_GROUPING_ID
FROM temp_re_split_input;
DROP TABLE temp_re_split_input;
DROP TABLE temp_all_concat_input;
-- note: table sequence generator should not be used, this is just an example that you need to update sequence if not using auto increment
UPDATE table_sequence_generator
SET ID_VAL = (SELECT COALESCE(MAX(CHUNK_ID) + 1, 1) FROM input_table)
WHERE ID_NAME = 'InputTableSequence';
COMMIT;
SET group_concat_max_len = 1024;
要将块大小增加到 6000,您只需更改
@chunk_size
变量:SET @chunk_size = 6000;
备注:
@chunk_size
可配置input_table
中删除GROUPING_ID
为空的所有值CHUNK_ID
值CHAR_LENGTH
代替LENGTH
函数也支持2字节特殊字符VARCHAR
用于存储长字符串,这是外部要求,但是 VALUE
列的类型可以替换为 TEXT
、MEDIUMTEXT
或 LONGTEXT
,您将不会遇到此问题chunks,既不需要input_table
,也可以直接在原表中使用column