Text 红移:插入时自动截断VARCHAR值,或者使用最大长度?

Text 红移:插入时自动截断VARCHAR值,或者使用最大长度?,text,amazon-redshift,Text,Amazon Redshift,执行插入时,红移不允许插入比表中目标字段长/宽的字符串值。注意: CREATE TEMPORARY TABLE test (col VARCHAR(5)); -- result: 'Table test created' INSERT INTO test VALUES('abcdefghijkl'); -- result: '[Amazon](500310) Invalid operation: value too long for type character varying(5);' 解

执行插入时,红移不允许插入比表中目标字段长/宽的字符串值。注意:

CREATE TEMPORARY TABLE test (col VARCHAR(5));
-- result: 'Table test created'

INSERT INTO test VALUES('abcdefghijkl');
-- result: '[Amazon](500310) Invalid operation: value too long for type character varying(5);'
解决方法之一是强制转换值:

INSERT INTO test VALUES('abcdefghijkl'::VARCHAR(5));
-- result: 'INSERT INTO test successful, 1 row affected'
令人恼火的是,现在我的所有代码都必须在每个VARCHAR字段的每个INSERT上都有这些cast语句,就像这样,否则应用程序代码必须在尝试构造查询之前截断字符串;无论哪种方式,这都意味着列的宽度规范必须进入应用程序代码,这很烦人

有没有更好的方法来使用红移?如果有一些选项,让服务器截短字符串并像MySQL那样执行(可能会发出警告),那就太好了

我可以做的一件事就是将这些特定字段声明为一个非常大的VARCHAR,甚至可能是65535(最大值)

我发现这种方法的一个缺点是,如果在group by/join/etc中使用此列,将导致性能下降:

(搜索VARCHAR)

我想知道,如果你不打算在GroupBy、join等中使用此字段,是否会有其他危害


在我的场景中需要注意的一些事情:是的,我真的不关心截断可能会丢失的额外字符,不,我没有办法强制执行源文本的长度。我从外部来源捕获消息和URL,这些消息和URL的字符长度通常在一定范围内,但有时会有更长的字符。在我们的应用程序中,字符串是否被截断并不重要。

自动截断字符串以匹配列宽的唯一方法是使用COPY命令和选项

将列中的数据截断为适当的字符数,以便 它符合柱的规格。仅适用于具有 VARCHAR或CHAR数据类型,行大小不超过4 MB

否则,您必须使用以下两种方法之一来处理字符串的长度:

  • 显式地将值强制转换为所需的VARCHAR:

    插入测试值(CAST('abcdefghijkl'作为VARCHAR(5))

  • 使用字符串函数截断字符串:

    插入测试值(左('abcdefghijkl',5))


  • 注意:
    CAST
    应该是您的第一个选项,因为它可以正确处理多字节字符<代码>左侧
    将根据字符数而不是字节数进行截断,如果字符串中有多字节字符,则可能会超出列的限制。

    谢谢,是的,这是我们很久以前就解决的问题。对于大批量插入,我们使用了COPY的truncate选项,这一点非常明显。对于在别处执行的其他插入和更新操作,我们正在使用
    操作符进行转换。转换时+1将处理字节。LEFT/RIGHT处理字符,因此如果源字符串是多字节字符串,LEFT/RIGHT可能会返回比预期wrt到字节长的VARCHAR。例如,LEFT(foobar,5)返回的字符串可能比VARCHAR(5)中存储的字符串长。
    create table analytics.testShort (a varchar(3));
    create table analytics.testLong (a varchar(4096));
    create table analytics.testSuperLong (a varchar(65535));
    
    insert into analytics.testShort values('abc'); 
    insert into analytics.testLong values('abc');
    insert into analytics.testSuperLong values('abc');
    
    -- Redshift reports the size for each table is the same, 4 mb