【问题标题】:array function returning empty数组函数返回空
【发布时间】:2017-03-21 10:51:20
【问题描述】:

这里的目的是让this answer返回数组而不是setof数据类型。

CREATE FUNCTION split_csvline(
  line text,                 -- the input CSV string
  delim_char char(1) = ',',  -- can be also E'\t', ';', '|', etc.
  quote_char char(1) = '"'   -- field quotation
) RETURNS  text[] AS $f$
  import csv
  row = csv.reader(
      [line], 
      quotechar=quote_char, 
      delimiter=delim_char, 
      skipinitialspace=True, 
      escapechar='\\'
  )
  next(row)
$f$ IMMUTABLE language PLpythonU;

SELECT split_csvline('a,b');  -- empty!

编辑

注意事项

这是一个关于“使用 Python 和 PostgreSQL”的问题。

我使用 PLpythonU 是因为工作人员使用 Python,而且 CSV 很复杂,需要可靠(多年测试)算法。

不需要解决方法,因为正在使用一个简单的解决方法:

CREATE FUNCTION split_csv_line(
  text, char(1) DEFAULT ',', char(1) DEFAULT '"'
) RETURNS text[] AS $f$
  SELECT x FROM split_csv($1,$2,$3) x LIMIT 1;
$f$ language SQL IMMUTABLE;

【问题讨论】:

  • 为什么不使用select regexp_split_to_array('a,b',',');
  • @BenH,CSV 很复杂,请参阅this regex,也许使用regexp_matches() ...
  • 我知道 csv 很复杂,但你应该考虑比'a,b'更好的样本
  • 您没有使用return 语句。恕我直言,几乎如果你想返回一些东西,所有的程序语言都要求这样做。

标签: python postgresql csv plpython


【解决方案1】:

csv.reader 函数返回一个reader 对象。 nextreader 对象方法:

create or replace function split_csvline(
    _line text,
    _delim_char char(1) = ',',  
    _quote_char char(1) = '"'
) returns  text[] as $f$
    import csv
    reader = csv.reader(
        [_line], 
        quotechar = _quote_char, 
        delimiter = _delim_char, 
        skipinitialspace = True, 
        escapechar = '\\'
    )
    return reader.next()
$f$ immutable language plpythonu;

select split_csvline('a,b');
 split_csvline 
---------------
 {a,b}

【讨论】:

    【解决方案2】:

    你可以使用 PL/pgSQL:

    CREATE OR REPLACE FUNCTION split_csvline(
       line text,                 -- the input CSV string
       delim_char char(1) = ',',  -- can be also E'\t', ';', '|', etc.
       quote_char char(1) = '"',  -- field quotation
       OUT result text[]
    ) LANGUAGE plpgsql AS
    $$DECLARE
       i integer;
       t text := '';
       c char(1);
       /*
        * 0 means unquoted
        * 1 means quoted
        * 2 means quoted, and we just read a quote
        */
       q integer := 0;
    BEGIN
       /* loop through the characters */
       FOR i IN 1..length(line) LOOP
          /* get i-th character */
          c := substring(line FROM i FOR 1);
          /* end of string is at an unquoted delimiter */
          IF c = delim_char AND q <> 1 THEN
             result := result || t;
             t := '';
             q := 0;
          ELSIF c = quote_char THEN
             CASE q
                WHEN 0 THEN
                   q := 1;
                WHEN 1 THEN
                   IF c = quote_char THEN
                      q := 2;
                   ELSE
                      t := t || c;
                   END IF;
                WHEN 2 THEN
                   q := 1;
                   t := t || quote_char;
             END CASE;
          ELSE
             IF q = 2 THEN
                q := 0;
             END IF;
             t := t || c;
          END IF;
       END LOOP;
       /* add the last string */
       result := result || t;
    END;$$;
    

    【讨论】:

    • 感谢@LaurenzAble!嗯……这个算法适用于任何 CSV 案例吗?甚至像this perl one 这样的简单算法也使用正则表达式...我试图使用regexp_matches() 但需要使?:^|,)(?=[^"]|(")?)"?((?(1)[^"]*|[^,"]*))"?(?=,|$) 适应POSIX...
    • 它应该适用于一切,除非我犯了编程错误。有时编写状态机比指定语法更简单。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-19
    相关资源
    最近更新 更多