回答:
私自身も同様の問題に取り組んでいましたが、関数のオーバーヘッドは必要ありませんでした。私は次のクエリを思いつきました:
SELECT myfield::integer FROM mytable WHERE myfield ~ E'^\\d+$';
Postgresはその条件文をショートカットするので、:: integerキャストに非整数が当たらないようにしてください。また、NULL値も処理します(正規表現とは一致しません)。
選択せずにゼロが必要な場合は、CASEステートメントが機能します。
SELECT CASE WHEN myfield~E'^\\d+$' THEN myfield::integer ELSE 0 END FROM mytable;
E'\\d{1,5}$'
。
{1,5}
桁数に関する上記の制限は、オーバーフローが心配な場合は良い考えですが、大きい数値をマスクするため、テーブルを変換する場合に問題が発生する可能性があります。個人的には、クエリエラーを事前に用意しておき、私の「整数」の一部が厄介であることを知っています(E'\\d{6,}$'
最初にを選択して確認することもできます)。
例外ブロックを使用できる独自の変換関数を作成することもできます。
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)
INSERT
か?
私は同じ種類のニーズを持っていて、これが私にとってうまくいくことがわかりました(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)
「悪い」(数字文字がまったくない)などのケースを含め、すべてのケースで0を与えない解決策に関するChris Cogdonの懸念に対処するために、次のように調整したステートメントを作成しました。
CAST((COALESCE(NULLIF(REGEXP_REPLACE(myfield, '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER);
これは、変換する値が「bad」などの数字以外の文字のみの場合に0が返されることを除いて、より単純なソリューションと同様に機能します。
db=> select CAST((COALESCE(NULLIF(REGEXP_REPLACE('no longer bad!', '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER);
coalesce
----------
0
(1 row)
これは多少ハックのように見えるかもしれませんが、私たちの場合、それは仕事を成し遂げました:
(0 || myfield)::integer
説明(Postgres 8.4でテスト済み):
上記の式はNULL
、myfield
およびの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
ではエラーメッセージが表示されます。
お役に立てれば。
SELECT CASE WHEN myfield="" THEN 0 ELSE myfield::integer END FROM mytable
私はPostgreSQLを使用したことがありませんが、マニュアルでSELECTクエリのIFステートメントの正しい構文を確認しました。
@マシューの答えは良いです。しかし、それはより簡単でより速くなることができます。そして、質問は空の文字列(''
)をに変換するように求めます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
その他の無効な入力に対して返されます。あらゆるデータ型変換に
簡単に適合できます。
例外ブロックに入るのはかなり高価です。空の文字列が一般的である場合、例外を発生させる前にそのケースをキャッチすることは理にかなっています。
空の文字列が非常にまれである場合、テストを例外句に移動することは価値があります。
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
次のコードは簡単で機能しています。元の回答はこちら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にそのテーブルの各クエリの単一行ごとにそれらの値を何度も変換するように強制しています。このテーブルのこの列に対して多くのクエリを実行すると、パフォーマンスが大幅に低下する可能性があります。
次の関数は
error_result
キャストできない結果にはデフォルト値()を使用します。abc
または999999999999999999999999999999999999999999
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;