根据块大小重新拆分 MySQL 中的 varchar 列值

问题描述 投票:0回答:1

我有这张表,其中通过在

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 中执行此操作。

mysql split partition varchar chunks
1个回答
0
投票

经过一些研究,我设法连接了这些值,然后在 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 x 50,如果 chunk 大小为 4000,则为 200k 个字符
  • 为 Oracle 兼容性设置了 4000 个字符的长度,但是此代码特定于 MySQL
  • 如上所述,此方法应保持块的正确顺序
  • @chunk_size
    可配置
  • 这可用于减少或增加块大小
  • 它将从
    input_table
    中删除
    GROUPING_ID
    为空的所有值
  • 会产生不同的
    CHUNK_ID
  • 最后一部分只是一个如何更新表序列的例子,那部分和重新插入可以根据需要改变
  • 使用
  • CHAR_LENGTH
    代替
    LENGTH
    函数也支持2字节特殊字符
  • 运行此脚本时不应在表中插入新数据
  • 在我的示例中,
    VARCHAR
    用于存储长字符串,这是外部要求,但是
    VALUE
    列的类型可以替换为
    TEXT
    MEDIUMTEXT
    LONGTEXT
    ,您将不会遇到此问题chunks,既不需要
    input_table
    ,也可以直接在原表中使用column
© www.soinside.com 2019 - 2024. All rights reserved.