如何将一个string转换为整型,并且在PostgreSQL中转换时出现错误0?
在postgres中我有一个varchar列的表。 数据应该是整数,我需要它在迭代types的查询。 有些值是空string。 下列:
SELECT myfield::integer FROM mytable
产生ERROR: invalid input syntax for integer: ""
如何查询一个强制转换,并在postgres中抛出时出错?
我只是自己摔跤类似的问题,但不希望一个函数的开销。 我想出了以下的查询:
SELECT myfield::integer FROM mytable WHERE myfield ~ E'^\\d+$';
Postgres快捷键的条件,所以你不应该得到任何非整数击中你的::整数铸造。 它也处理NULL值(它们不会匹配正则expression式)。
如果你想要零而不是select,那么CASE语句应该工作:
SELECT CASE WHEN myfield~E'^\\d+$' THEN myfield::integer ELSE 0 END FROM mytable;
您也可以创build自己的转换函数,在其中您可以使用exception块:
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;
testing:
=# 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)
我有同样的需求,发现这对我来说很好(postgres 8.4):
CAST((COALESCE(myfield,'0')) AS INTEGER)
一些testing用例来演示:
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”文本/ varchar值也会给数字
db=> select CAST(REGEXP_REPLACE(COALESCE('b3ad5','0'), '[^0-9]+', '', 'g') AS INTEGER); regexp_replace ---------------- 35 (1 row)
为了解决Chris Cogdon关于所有情况下不给0的解决scheme的顾虑,包括诸如“坏”(根本没有数字字符)的情况,我做了这个调整陈述:
CAST((COALESCE(NULLIF(REGEXP_REPLACE(myfield, '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER);
它的作用类似于更简单的解决scheme,除非在转换的值是非数字字符时才会给出0,例如“bad”:
db=> select CAST((COALESCE(NULLIF(REGEXP_REPLACE('no longer bad!', '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER); coalesce ---------- 0 (1 row)
这可能有些黑客,但是在我们的案例中完成了这项工作:
(0 || myfield)::integer
解释(testingPostgres 8.4):
上面提到的expression式在myfield
为NULL值,在空string中为0
(这个确切的行为可能会或可能不符合你的用例)。
SELECT id, (0 || values)::integer from test_table ORDER BY id
testing数据:
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 | ---------------------
而只selectvalues::integer
将导致错误消息。
希望这可以帮助。
SELECT CASE WHEN myfield="" THEN 0 ELSE myfield::integer END FROM mytable
我从来没有使用过PostgreSQL,但是我在SELECT查询中检查了手册中正确的IF语句语法。
@马修的答案是好的。 但它可以更简单,更快。 问题是要将空string( ''
)转换为0
,而不是其他“无效input语法”或“超出范围”input:
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;
这将为空string返回0
,对于任何其他无效input返回NULL
。
它可以很容易地适应任何数据types转换 。
input一个exception块实际上比较昂贵。 如果空string是常见的,那么在引发exception之前捕获该情况是有意义的。
如果空string非常罕见,那么将testing移到exception子句是值得的。
CREATE OR REPLACE FUNCTION parse_int(s TEXT) RETURNS INT AS $$ BEGIN RETURN regexp_replace(('0' || s), '[^\d]', '', 'g')::INT; END; $$ LANGUAGE plpgsql;
如果inputstring中没有数字,此函数将始终返回0
。
SELECT parse_int('test12_3test');
将返回123
我发现下面的代码很容易和工作。 原始答案在这里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)
希望能帮助到你
如果数据应该是整数,并且只需要这些值作为整数,为什么不去整个英里并将列转换为整数列?
然后,您可以在将数据插入到表中的系统的位置将非法值转换为零。
通过上面的转换,你迫使Postgres为每个查询中的每一行重复地转换这些值 – 如果你在这个表中对这个列进行大量的查询,这会严重降低性能。
这也应该做这个工作,但这是横跨SQL,而不是postgres具体。
select avg(cast(mynumber as numeric)) from my table