如何在使用PostgreSQL进行转换时将字符串转换为整数并且为0时出现错误?

时间:2010-01-17 21:17:30

标签: sql postgresql casting

在PostgreSQL中,我有一个带varchar列的表。数据应该是整数,我在查询中需要整数类型。有些值是空字符串。 以下内容:

SELECT myfield::integer FROM mytable

收益ERROR: invalid input syntax for integer: ""

如何在postgres中投射期间查询演员表并且出现错误时为0?

14 个答案:

答案 0 :(得分:137)

我自己只是在解决类似问题,但不想要功能的开销。我提出了以下问题:

SELECT myfield::integer FROM mytable WHERE myfield ~ E'^\\d+$';

Postgres快捷键其条件,所以你不应该得到任何非整数命中你的::整数。它还处理NULL值(它们与正则表达式不匹配)。

如果你想要零而不是不选择,那么CASE语句应该有效:

SELECT CASE WHEN myfield~E'^\\d+$' THEN myfield::integer ELSE 0 END FROM mytable;

答案 1 :(得分:84)

你也可以创建自己的转换函数,可以使用异常块:

CREATE OR REPLACE FUNCTION convert_to_integer(v_input text)
RETURNS INTEGER AS $$
DECLARE v_int_value INTEGER DEFAULT NULL;
BEGIN
    BEGIN
        v_int_value := v_input::INTEGER;
    EXCEPTION WHEN OTHERS THEN
        RAISE NOTICE 'Invalid integer value: "%".  Returning NULL.', v_input;
        RETURN NULL;
    END;
RETURN v_int_value;
END;
$$ LANGUAGE plpgsql;

测试:

=# select convert_to_integer('1234');
 convert_to_integer 
--------------------
               1234
(1 row)

=# select convert_to_integer('');
NOTICE:  Invalid integer value: "".  Returning NULL.
 convert_to_integer 
--------------------

(1 row)

=# select convert_to_integer('chicken');
NOTICE:  Invalid integer value: "chicken".  Returning NULL.
 convert_to_integer 
--------------------

(1 row)

答案 2 :(得分:24)

我有同样的需求,发现这对我有用(postgres 8.4):

CAST((COALESCE(myfield,'0')) AS INTEGER)

要演示的一些测试用例:

db=> select CAST((COALESCE(NULL,'0')) AS INTEGER);
 int4
------
    0
(1 row)

db=> select CAST((COALESCE('','0')) AS INTEGER);
 int4
------
    0
(1 row)

db=> select CAST((COALESCE('4','0')) AS INTEGER);
 int4
------
    4
(1 row)

db=> select CAST((COALESCE('bad','0')) AS INTEGER);
ERROR:  invalid input syntax for integer: "bad"

如果您需要处理字段具有非数字文本的可能性(例如“100bad”),您可以使用regexp_replace在强制转换前删除非数字字符。

CAST(REGEXP_REPLACE(COALESCE(myfield,'0'), '[^0-9]+', '', 'g') AS INTEGER)

然后像“b3ad5”这样的text / varchar值也会给出数字

db=> select CAST(REGEXP_REPLACE(COALESCE('b3ad5','0'), '[^0-9]+', '', 'g') AS INTEGER);
 regexp_replace
----------------
             35
(1 row)

为了解决Chris Cogdon对解决方案的关注,不解决所有情况,包括诸如“坏”(完全没有数字字符)之类的情况,我做了这个调整后的陈述:

CAST((COALESCE(NULLIF(REGEXP_REPLACE(myfield, '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER);

它的工作方式类似于更简单的解决方案,除非转换的值仅为非数字字符时给出0,例如“bad”:

db=> select CAST((COALESCE(NULLIF(REGEXP_REPLACE('no longer bad!', '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER);
     coalesce
----------
        0
(1 row)

答案 3 :(得分:18)

这可能有点像黑客,但它完成了我们的工作:

(0 || myfield)::integer

解释(在Postgres 8.4上测试):

对于空字符串,上面提到的表达式为NULLmyfield中的NULL值产生0(这种确切的行为可能适合您的用例,也可能不适合您的用例)。

SELECT id, (0 || values)::integer from test_table ORDER BY id

测试数据:

CREATE TABLE test_table
(
  id integer NOT NULL,
  description character varying,
  "values" character varying,
  CONSTRAINT id PRIMARY KEY (id)
)

-- Insert Test Data
INSERT INTO test_table VALUES (1, 'null', NULL);
INSERT INTO test_table VALUES (2, 'empty string', '');
INSERT INTO test_table VALUES (3, 'one', '1');

查询将产生以下结果:

 ---------------------
 |1|null        |NULL|
 |2|empty string|0   |
 |3|one         |1   |
 ---------------------

而仅选择values::integer将导致错误消息。

希望这有帮助。

答案 4 :(得分:3)

SELECT CASE WHEN myfield="" THEN 0 ELSE myfield::integer END FROM mytable

我从未使用过PostgreSQL,但我在manual检查了SELECT查询中IF语句的正确语法。

答案 5 :(得分:3)

@Matthew's answer很好。但它可以更简单,更快捷。问题要求将空字符串('')转换为0,而不是其他“无效输入语法”或“超出范围”输入:

CREATE OR REPLACE FUNCTION convert_to_int(text)
  RETURNS int AS
$func$
BEGIN
   IF $1 = '' THEN  -- special case for empty string like requested
      RETURN 0;
   ELSE
      RETURN $1::int;
   END IF;

EXCEPTION WHEN OTHERS THEN
   RETURN NULL;  -- NULL for other invalid input

END
$func$  LANGUAGE plpgsql IMMUTABLE;

这会返回0表示空字符串,NULL表示任何其他无效输入 它可以轻松适应 任何数据类型转换

输入例外程序块要贵得多。如果空字符串是 common ,则在引发异常之前捕获该情况是有意义的 如果空字符串非常罕见,则将测试移至异常子句是值得的。

答案 6 :(得分:1)

CREATE OR REPLACE FUNCTION parse_int(s TEXT) RETURNS INT AS $$
BEGIN
  RETURN regexp_replace(('0' || s), '[^\d]', '', 'g')::INT;
END;
$$ LANGUAGE plpgsql;

如果输入字符串中没有数字,则此函数将始终返回0

SELECT parse_int('test12_3test');

将返回123

答案 7 :(得分:1)

我发现以下代码简单易用。原始答案在https://www.postgresql.org/message-id/371F1510.F86C876B@sferacarta.com

prova=> create table test(t text, i integer);
CREATE

prova=> insert into test values('123',123);
INSERT 64579 1

prova=> select cast(i as text),cast(t as int)from test;
text|int4
----+----
123| 123
(1 row)

希望有所帮助

答案 8 :(得分:1)

SUBSTRING在某些情况下可能会有所帮助,您可以限制int的大小。

SELECT CAST(SUBSTRING('X12312333333333', '([\d]{1,9})') AS integer);

答案 9 :(得分:1)

最后,我设法忽略了无效字符并只获取数字以将文本转换为数字。

SELECT (NULLIF(regexp_replace(split_part(column1, '.', 1), '\D','','g'), '') 
    || '.' || COALESCE(NULLIF(regexp_replace(split_part(column1, '.', 2), '\D','','g'),''),'00')) AS result,column1
FROM (VALUES
    ('ggg'),('3,0 kg'),('15 kg.'),('2x3,25'),('96+109'),('1.10'),('132123')
) strings;  

答案 10 :(得分:0)

如果数据应该是整数,并且您只需要将这些值作为整数,为什么不进行整个步骤并将列转换为整数列?

然后,您可以在将数据插入表格的系统中将非法值转换为零一次。

通过上述转换,您强制Postgres为该表的每个查询中的每一行反复转换这些值 - 如果您对此表中的此列执行大量查询,这会严重降低性能。

答案 11 :(得分:0)

我也有同样的需求,但适用于JPA 2.0和Hibernate 5.0.2:

SELECT p FROM MatchProfile p WHERE CONCAT(p.id, '') = :keyword

创造奇迹。我认为它也适用于LIKE。

答案 12 :(得分:0)

以下功能可以

  • 对无法转换的结果使用默认值(error_result),例如abc999999999999999999999999999999999999999999
  • null保留为null
  • 修剪输入中的空格和其他空格
  • 强制转换为有效bigints的值与lower_bound进行比较,例如仅强制使用正值
CREATE OR REPLACE FUNCTION cast_to_bigint(text) 
RETURNS BIGINT AS $$
DECLARE big_int_value BIGINT DEFAULT NULL;
DECLARE error_result  BIGINT DEFAULT -1;
DECLARE lower_bound   BIGINT DEFAULT 0;
BEGIN
    BEGIN
        big_int_value := CASE WHEN $1 IS NOT NULL THEN GREATEST(TRIM($1)::BIGINT, lower_bound) END;
    EXCEPTION WHEN OTHERS THEN
        big_int_value := error_result;
    END;
RETURN big_int_value;
END;

答案 13 :(得分:-3)

这也可以完成这项工作,但这是跨越SQL而不是特定于postgres。

select avg(cast(mynumber as numeric)) from my table