即使值在范围内,Redshift 也会抛出“值对于字符类型字符变化(100)来说太长”的错误

nig*_*unt 4 redshift

我知道这个错误消息的含义Value too long for character type character varying(100)。因此,我经常寻找导致问题的行,并根据要求适当地修复它们。

但我今天遇到了一个奇怪的问题,即使没有粗行,也会发生错误。

插入查询失败:

INSERT INTO training.archive_temp1 (id, booking, email, pcd_temp, property_id)
WITH x_pcd AS (
    SELECT e.id,
        e.booking,
        e.email,
        CASE
            WHEN LENGTH(e.pch) > 0 THEN (e.pch || ':' || e.pcd)
            ELSE e.pcd
        END AS pcd_temp,
        e.pcd
    FROM public.extracts_temp AS e WHERE e.id BETWEEN 274939128 AND 275083166
)
SELECT x.id,
    x.booking,
    x.email,
    x.pcd_temp,
    COALESCE(c2.property_id, c.property_id)
FROM x_pcd AS x
         LEFT JOIN public.property_codes AS c ON x.pcd_temp = c.code
         LEFT JOIN public.property_codes AS c2 ON x.pcd = c2.code
WHERE COALESCE(c2.property_id,c.property_id, 0) <> 0;
Run Code Online (Sandbox Code Playgroud)

如果我改x.email一下x.email::varchar(100)就可以了。

这就是问题所在。

SELECT max(length(email)) FROM training.archive_temp1;
-- returns 64
Run Code Online (Sandbox Code Playgroud)

诡异的。所以我检查了

SELECT max(length(email)) FROM (
SELECT e.id,
        e.booking,
        e.email,
        CASE
            WHEN LENGTH(e.pch) > 0 THEN (e.pch || ':' || e.pcd)
            ELSE e.pcd
        END AS pcd_temp,
        e.pcd
    FROM public.extracts_temp AS e WHERE e.id BETWEEN 274939128 AND 275083166
)
-- returns 66
Run Code Online (Sandbox Code Playgroud)

如果没有行超过 100 个字符限制,为什么会抛出错误?这里发生了什么?

如果您需要我分享您的任何疑问的结果,请告诉我。由于行数在 100000 范围内,因此无法在此处共享整个数据,并且如果我可以共享该案例的最小可验证示例,我就不会问这个问题。

nig*_*unt 9

Redshift 可以将多字节字符串存储到 varchar 字段中。但如果你定义你的字段,varchar(100)它并不意味着 100 个字符。相反,它意味着 100 个字节。因此,如果字符串中的所有字符都是两个字节字符,则该字段最多可以存储 50 个字符。

文档来看,

使用 VARCHAR 或 CHARACTER VARYING 列存储具有固定限制的可变长度字符串。这些字符串不会用空格填充,因此 VARCHAR(120) 列最多包含 120 个单字节字符、60 个两字节字符、40 个三字节字符或 30 个四字节字符。

问题是LENGTH函数仅返回字符数,而不返回不包括尾随空格的字节数。因此,获取多字节字符的长度仅返回 1。此处对此进行了记录。

替代的OCTET_LENGTH可以返回字节数而不是字符数。

运行 OCTET_LENGTH 发现麻烦制造者,现已修复。