微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

postgresql奇怪的类型为numeric的无效输入语法:“”而value不是空的varchar

我正在尝试调试我自己没有制作的功能( dms2dd).我制作了自己的测试功能(见下文)并将我的问题归结为特定的行/值.

如果我运行以下查询

SELECT "Lat","Long",test_dolf("Lat"),test_dolf("Long") FROM pawikan WHERE "Lat" IS NOT NULL AND "Long" IS NOT NULL ORDER BY index LIMIT 1 OFFSET 29130

我得到以下输出

'N6° 6' 9.4824"';'E118° 26' 49.1172'' ';'9.4824';'49.1172'

这正是我所期待的.
但是使用以下查询

SELECT "Lat",CAST(test_dolf("Lat") as numeric),test_dolf("Long") FROM pawikan WHERE "Lat" IS NOT NULL AND "Long" IS NOT NULL ORDER BY index  LIMIT 1 OFFSET 29130

我收到了错误

ERROR: invalid input Syntax for type numeric: ""
sql state: 22P02

错误表明我尝试转换为数字的varchar值为空,但正如您从上一个查询中看到的那样,它不是.它只是一个有效的数字varchar.实际上,如果我复制粘贴值并运行:

SELECT CAST('9.4824' AS numeric);

它完全有效,查询实际上会生成一个有效的数字.
更重要的是,如果我将第一个查询的结果存储在中间表中:

SELECT "Lat",test_dolf("Lat") as lat_sec,test_dolf("Long") as long_sec INTO dms2dd_test FROM pawikan WHERE "Lat" IS NOT NULL AND "Long" IS NOT NULL ORDER BY index LIMIT 11 OFFSET 29120

然后发出一个

SELECT CAST(long_sec as numeric),CAST(lat_sec AS numeric) FROM dms2dd_test;

它完全有效.
即使这样也可以:

SELECT test_dolf(E'N6° 6\' 9.4824"')::numeric as lat_sec

那么这里出了什么问题?它看起来像我转换为数字的第二个查询,一个不同的值传递给我的函数,但我测试了排序列(索引),它只包含唯一的bigints.

这是test_dolf函数代码

CREATE OR REPLACE FUNCTION public.test_dolf(strdegminsec character varying)
  RETURNS varchar AS
$BODY$
    DECLARE
       i               numeric;
       intDmsLen       numeric;          -- Length of original string
       strCompasspoint Char(1);
       strnorm         varchar(16) = ''; -- Will contain normalized string
       strDegMinSecB   varchar(100);
       blnGotSeparator integer;          -- Keeps track of separator sequences
       arrDegMinSec    varchar[];        -- TYPE stringarray is table of varchar(2048) ;
       strChr          Char(1);
    BEGIN
       strDegMinSec := regexp_replace(replace(strdegminsec,E'\'\'','"'),' "([0-9]+)',E' \\1"');
       -- Remove leading and trailing spaces
       strDegMinSecB := REPLACE(strDegMinSec,' ','');
       intDmsLen := Length(strDegMinSecB);

       blnGotSeparator := 0; -- Not in separator sequence right Now

       -- Loop over string,replacing anything that is not a digit or a
       -- decimal separator with
       -- a single blank
       FOR i in 1..intDmsLen LOOP
          -- Get current character
          strChr := SubStr(strDegMinSecB,i,1);
          -- either add character to normalized string or replace
          -- separator sequence with single blank         
          If strpos('0123456789,.',strChr) > 0 Then
             -- add character but replace comma with point
             If (strChr <> ',') Then
                strnorm := strnorm || strChr;
             Else
                strnorm := strnorm || '.';
             End If;
             blnGotSeparator := 0;
          ElsIf strpos('neswnesW',strChr) > 0 Then -- Extract Compass Point if present
            strCompasspoint := strChr;
          Else
             -- ensure only one separator is replaced with a blank -
             -- suppress the rest
             If blnGotSeparator = 0 Then
                strnorm := strnorm || ' ';
                blnGotSeparator := 0;
             End If;
          End If;
       End Loop;

       -- Split normalized string into array of max 3 components
       arrDegMinSec := string_to_array(strnorm,' ');
       return arrDegMinSec[3];
    End 
$BODY$
  LANGUAGE plpgsql IMMUTABLE
  COST 100;

解决方法

您得到的错误如下:

ERROR: invalid input Syntax for type numeric: ""

因此,它试图将空字符串转换为数字值.使用NULLIF功能解决这个问题怎么样?

SELECT "Lat",CAST(NULLIF(test_dolf("Lat"),'') as numeric),test_dolf("Long") FROM pawikan WHERE "Lat" IS NOT NULL AND "Long" IS NOT NULL ORDER BY index  LIMIT 1 OFFSET 29130;

此外,您可能希望查看执行计划以了解此问题.可能发生的是LIMIT和OFFSET刚刚在施法后执行.这解释了为什么你没有看到空字符串的行.

编辑

糟糕,我应该在发布之前阅读你的答案.无论如何,您仍然可以使用NULLIF来解决您的问题.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐