45

特定の文字列が SQL ステートメントで数値 (整数または浮動小数点) として解釈できるかどうかを判断する必要があります。次のように:

SELECT AVG(CASE WHEN x ~ '^[0-9]*.?[0-9]*$' THEN x::float ELSE NULL END) FROM test

これには Postgres のパターン マッチングを使用できることがわかりました。そのため、この場所で与えられたステートメントを適応させて、浮動小数点数を組み込みました。これは私のコードです:

WITH test(x) AS (
    VALUES (''), ('.'), ('.0'), ('0.'), ('0'), ('1'), ('123'),
    ('123.456'), ('abc'), ('1..2'), ('1.2.3.4'))

SELECT x
     , x ~ '^[0-9]*.?[0-9]*$' AS isnumeric
FROM test;

出力:

    x    | isnumeric 
---------+-----------
         | t
 .       | t
 .0      | t
 0.      | t
 0       | t
 1       | t
 123     | t
 123.456 | t
 abc     | f
 1..2    | f
 1.2.3.4 | f
(11 rows)

ご覧のとおり、最初の 2 つの項目 (空の文字列''と唯一のピリオド'.') は、数値型として誤分類されています (実際にはそうではありません)。現時点ではこれ以上近づくことはできません。どんな助けでも大歓迎です!


更新この回答(およびそのコメント) に基づいて、パターンを次のように調整しました。

WITH test(x) AS (
    VALUES (''), ('.'), ('.0'), ('0.'), ('0'), ('1'), ('123'),
    ('123.456'), ('abc'), ('1..2'), ('1.2.3.4'), ('1x234'), ('1.234e-5'))

SELECT x
     , x ~ '^([0-9]+[.]?[0-9]*|[.][0-9]+)$' AS isnumeric
FROM test;

これにより、次のことが得られます。

     x    | isnumeric 
----------+-----------
          | f
 .        | f
 .0       | t
 0.       | t
 0        | t
 1        | t
 123      | t
 123.456  | t
 abc      | f
 1..2     | f
 1.2.3.4  | f
 1x234    | f
 1.234e-5 | f
(13 rows)

私が今見ているように、科学的表記法と負の数にはまだいくつかの問題があります。

4

5 に答える 5

100

お気づきかもしれませんが、正規表現ベースの方法を正しく行うことはほとんど不可能です。たとえば、テストでは、1.234e-5実際には有効な数値ではないことが示されています。また、負の数を逃しました。数値のように見えても、格納しようとするとオーバーフローが発生する場合はどうすればよいでしょうか?

代わりに、実際にキャストしようとする関数を作成しNUMERIC(またはFLOATタスクが必要な場合)、このキャストが成功したかどうかに応じてTRUEorを返すことをお勧めします。FALSE

このコードは機能を完全にシミュレートしますISNUMERIC():

CREATE OR REPLACE FUNCTION isnumeric(text) RETURNS BOOLEAN AS $$
DECLARE x NUMERIC;
BEGIN
    x = $1::NUMERIC;
    RETURN TRUE;
EXCEPTION WHEN others THEN
    RETURN FALSE;
END;
$$
STRICT
LANGUAGE plpgsql IMMUTABLE;

データに対してこの関数を呼び出すと、次の結果が得られます。

WITH test(x) AS ( VALUES (''), ('.'), ('.0'), ('0.'), ('0'), ('1'), ('123'),
  ('123.456'), ('abc'), ('1..2'), ('1.2.3.4'), ('1x234'), ('1.234e-5'))
SELECT x, isnumeric(x) FROM test;

    x     | isnumeric
----------+-----------
          | f
 .        | f
 .0       | t
 0.       | t
 0        | t
 1        | t
 123      | t
 123.456  | t
 abc      | f
 1..2     | f
 1.2.3.4  | f
 1x234    | f
 1.234e-5 | t
 (13 rows)

より正確で読みやすいだけでなく、データが実際に数値である場合は、より高速に動作します。

于 2013-04-25T03:58:01.130 に答える
10

問題は、小数点の両側にある 2 つの 0 以上の [0-9] 要素です。|番号識別行で論理 OR を使用する必要があります。

~'^([0-9]+\.?[0-9]*|\.[0-9]+)$'

これにより、小数点のみが有効な数値として除外されます。

于 2013-04-24T15:30:16.660 に答える