如何将字符串强制转换为整数,并在使用PostgreSQL强制转换时出错时使用0?

如何将字符串强制转换为整数,并在使用PostgreSQL强制转换时出错时使用0?,sql,postgresql,casting,Sql,Postgresql,Casting,在PostgreSQL中,我有一个带有varchar列的表。数据应该是整数,我需要在查询中使用整数类型。有些值是空字符串。 以下是: SELECT myfield::integer FROM mytable 产生错误:整数的输入语法无效:“” 在postgres中进行强制转换时,如果出现错误,如何查询强制转换并使用0?选择case WHEN myfield=”“,然后选择0 ELSE myfield::integer END FROM mytable 我从未使用过PostgreSQL,但我检查

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

SELECT myfield::integer FROM mytable
产生
错误:整数的输入语法无效:“”


在postgres中进行强制转换时,如果出现错误,如何查询强制转换并使用0?

选择case WHEN myfield=”“,然后选择0 ELSE myfield::integer END FROM mytable


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

如果数据应该是整数,而您只需要将这些值作为整数,为什么不尽全力将列转换为整数列呢

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


通过上述转换,您将迫使Postgres对该表的每个查询中的每一行反复转换这些值-如果您对该表中的该列进行大量查询,这将严重降低性能。

您还可以创建自己的转换函数,在其中可以使用异常块:

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)

我自己也在努力解决一个类似的问题,但我不希望函数的开销。我提出了以下问题:

SELECT myfield::integer FROM mytable WHERE myfield ~ E'^\\d+$';
Postgres简化了它的条件,所以您不应该得到任何非整数命中::integer强制转换。它还处理空值(它们与regexp不匹配)

如果您想要零而不是不选择,那么CASE语句应该可以:

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

这也可以完成任务,但这是跨SQL的,而不是特定于postgres的

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

这可能有点像黑客,但在我们的案例中,它完成了任务:

(0 || myfield)::integer
解释(在Postgres 8.4上测试):

上述表达式为
myfield
中的NULL值生成
NULL
,为空字符串生成
0
(这种确切的行为可能适合也可能不适合您的用例)

测试数据:

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
将导致错误消息


希望这能有所帮助。

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

一些测试用例用于演示:

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)
然后,text/varchar值(如“b3ad5”)也将给出数字

db=> select CAST(REGEXP_REPLACE(COALESCE('b3ad5','0'), '[^0-9]+', '', 'g') AS INTEGER);
 regexp_replace
----------------
             35
(1 row)
为了解决Chris Cogdon对解决方案没有为所有情况(包括“坏”(完全没有数字字符)提供0的担忧,我做了以下调整声明:

CAST((COALESCE(NULLIF(REGEXP_REPLACE(myfield, '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER);
它的工作原理与更简单的解决方案类似,只是当要转换的值仅为非数字字符(如“bad”)时,它将给出0:

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

选择parse_int('test12_3test')


将返回
123

我发现下面的代码简单有效。原来的答案在这里

希望对你有帮助。很好。但它可以更简单、更快。该问题要求将空字符串(
'
)转换为
0
,而不是其他“无效输入语法”或“超出范围”输入:

对于空字符串,返回
0
;对于任何其他无效输入,返回
NULL

它可以轻松地适应任何数据类型转换

输入异常块的成本要高得多。如果空字符串很常见,则在引发异常之前捕获该情况是有意义的。

如果空字符串非常罕见,那么将测试移到exception子句是值得的。

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

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

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

子字符串在某些情况下可能会有所帮助,您可以限制int的大小

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

下面的函数不起作用

  • 对不可强制转换的结果使用默认值(
    error_result
    ),例如
    abc
    99999999999999999999999999
  • null
    保持为
    null
  • 修剪输入中的空格和其他空白
  • 将铸造为有效的
    bigint
    值与
    下限
    进行比较,例如仅强制正值
创建或替换函数强制转换为(文本)
返回BIGINT作为$$
声明big_int_值BIGINT默认为NULL;
声明错误\u result BIGINT DEFAULT-1;
声明下限BIGINT默认值为0;
开始
开始
big_int_value:=当$1不为空时,则为最大值(TRIM($1)::BIGINT,下限)结束;
当其他人
big_int_值:=错误结果;
结束;
返回大整数值;
结束;

最后,我设法忽略了无效字符,只获得了将文本转换为数字的数字

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;  

这适用于现在的桌子。我有点害怕将来它可能包含非数值。我更喜欢一个类似于try/catch的解决方案,但这确实奏效了。谢谢。也许你可以使用正则表达式,但那可能会很昂贵。如果是解决方案,也可以接受答案:)原则上你是对的,但在这个特定场景中,我必须优化应用程序中的单个慢速查询。我不知道处理数据输入的代码是如何工作的。我不想碰它。到目前为止,我重写的查询工作正常,但我希望它不会在不可预见的情况下中断。重新设计应用程序不是一个选项,即使这似乎是最明智的事情。我强烈建议采纳Matthew的建议。此解决方案存在看起来像数字但大于整数中最大值的字符串问题
CREATE OR REPLACE FUNCTION parse_int(s TEXT) RETURNS INT AS $$
BEGIN
  RETURN regexp_replace(('0' || s), '[^\d]', '', 'g')::INT;
END;
$$ LANGUAGE plpgsql;
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)
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;
SELECT p FROM MatchProfile p WHERE CONCAT(p.id, '') = :keyword
SELECT CAST(SUBSTRING('X12312333333333', '([\d]{1,9})') AS integer);
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;