sql - 如何防止从 Informix 存储过程返回的长文本值中出现换行符

标签 sql database stored-procedures informix

我正在编写一个模拟 Informix UNLOAD 的存储过程,这样我就可以将输出放入一个竖线分隔的文本文件中,以便传输到另一个系统。我的过程按预期工作,但是当我将输出重定向到我的 shell 脚本中的文本文件时,这些行在 66 个字符后中断。我需要每条记录都在自己的行上,记录中没有换行符。

它为每条记录返回的文本字符串最长可达 350 个字符。是否存在导致这种情况发生的 Informix 设置?我的 shell 脚本中有什么?

整个过程如下。我还添加了代码,展示了我如何从 shell 脚本调用此 SP。

我们使用的是 Solaris 10 和 Informix IDS 11.70。

我看到了 answer关于之前在存储过程中执行 UNLOAD 的 SO 问题。目前,首选是避免使用临时表和外部表。 (但如果我们不能让这种方法起作用,我们可能会回到那个解决方案。)

# Real script receives these as args or calculates using today's date
begin_date="2019-04-26 00:00:00"
end_date="2019-04-26 23:59:59"
dbname="mydatabase"
STORED_PROCEDURE="sp_unload_mytable"
OUTFILE="return.dat"

rm -f $OUTFILE
echo "execute procedure ${STORED_PROCEDURE}('${begin_date}','${end_date}') " | dbaccess $dbname \
| sed 's,(expression),,' | sed 's/,$//' | sed -e '/^$/d' | sed 's/^[ ]*//' > $OUTFILE
create procedure sp_unload_mytable(start_date datetime year to second, end_date datetime year to second)
   returning lvarchar(500);

   DEFINE p_rep_serial      integer;
   DEFINE p_post_flag       integer;
   DEFINE p_recording_date  varchar(8);
   DEFINE p_lastname        varchar(35);
   DEFINE p_firstname       varchar(20);
   DEFINE p_middlename      varchar(20);
   DEFINE p_generation      varchar(4);
   DEFINE p_role        varchar(8);
   DEFINE p_corporperson    varchar(1);
   DEFINE p_party_type      varchar(1);
   DEFINE p_b           varchar(5);
   DEFINE p_p           varchar(4);
   DEFINE p_item_number     varchar(4);
   DEFINE p_i_code          varchar(3);
   DEFINE p_i_desc          varchar(10);
   DEFINE p_par_id      varchar(12);
   DEFINE p_ref_b               varchar(5);
   DEFINE p_ref_p           varchar(4);
   DEFINE p_remark_1        varchar(20);
   DEFINE p_remark_2        varchar(20);
   DEFINE p_i_id            varchar(10);
   DEFINE p_ret_code        varchar(12);
   DEFINE p_nbr_of_attempts varchar(12);
   DEFINE p_insert_timestamp    datetime year to second;
   DEFINE p_edit_flag       varchar(12);
   DEFINE p_document_id     varchar(12);
   DEFINE p_version     varchar(6);
   DEFINE p_attempts        varchar(6);
   DEFINE p_return      lvarchar(500);

   FOREACH SELECT rep_serial, post_flag, nvl(recording_date, ""),
        nvl(lastname, ""), nvl(firstname, ""), nvl(middlename, ""), 
        nvl(trim(generation), ""), nvl(trim(role), ""), 
        nvl(trim(corporperson), ""), nvl(trim(party_type), ""), 
                  nvl(trim(b), ""), nvl(trim(p), ""), nvl(trim(item_number), ""), 
                  nvl(trim(i_code), ""), nvl(trim(i_desc), ""), 
                  nvl(par_id, ""), nvl(trim(ref_b), ""), 
                  nvl(trim(ref_p), ""), nvl(remark_1, ""), nvl(remark_2, ""), 
                  nvl(i_id, ""), nvl(ret_code, ""), nvl(nbr_of_attempts, ""), 
                  nvl(insert_timestamp, ""), nvl(edit_flag, ""), nvl(document_id, ""), 
                  nvl(version, ""), nvl(attempts, "")
        INTO p_rep_serial, p_post_flag, p_recording_date, p_lastname, p_firstname, 
             p_middlename, p_generation, p_role, p_corporperson, p_party_type, 
             p_b, p_p, p_item_number, p_i_code, p_i_desc, 
             p_par_id, p_ref_b, p_ref_p, p_remark_1, 
             p_remark_2, p_i_id, p_ret_code, p_nbr_of_attempts, 
             p_insert_timestamp, p_edit_flag, p_document_id, p_version, p_attempts
        from mytable
        where insert_timestamp between start_date and end_date

        LET p_return = p_rep_serial || "|" || p_post_flag || "|" || p_recording_date || "|" || p_lastname || "|" || p_firstname || "|" || p_middlename || "|" || p_generation || "|" || p_role || "|" || p_corporperson || "|" || p_party_type || "|" || p_b || "|" || p_p || "|" || p_item_number || "|" || p_i_code || "|" || p_i_desc || "|" || p_par_id || "|" || p_ref_b || "|" || p_ref_p || "|" || p_remark_1 || "|" || p_remark_2 || "|" || p_i_id || "|" || p_ret_code || "|" || p_nbr_of_attempts || "|" || p_insert_timestamp || "|" || p_edit_flag || "|" || p_document_id || "|" || p_version || "|" || p_attempts;

        RETURN p_return WITH RESUME;

   END FOREACH;

end procedure;

最佳答案

导致问题的是 DB-Access。

如果您使用的是足够新的 Informix 版本(12.10.xC12 或 14.10.xC1 或更高版本,在每个版本系列中),您可以使用环境变量 DBACCESS_COLUMNS 来设置有效“屏幕”(输出)的宽度。但是,如果数据本身包含换行符,那么这些将反射(reflect)在输出中。除了将输出强制转换为 JSON(这不是特别容易,但如果您好奇的话可以查找 genBSON),我不知道有什么方法可以删除换行符或用 \替换它们n 或类似的,除了通过后处理 DB-Access 输出。

由于您的 Informix (11.70) 版本太旧,无法支持 DBACCESS_COLUMNS,我不确定是否有真正好的替代方案。

必要时,您可以使用我的 SQLCMD程序(与 Microsoft 的同名 johnny-come-lately interloper 无关)。要在那里获得它,您必须加入 IIUG(国际 Informix 用户组),它是免费的并且不涉及太多电子邮件(除非您订阅任何邮件列表,否则每月一两封)。 SQLCMD 优于 DB-Access 的优点是它会自动执行“尽可能宽”的输出,但它没有“不直接包含换行符”的输出模式,除非通过它的 JSON 样式输出(我看到我需要在 v91.03 中修复错误,它比 IIUG 网站上的更新——目前它不是一个足够有用的选项)。我会考虑添加一个“C 风格转义输出”选项(或者它可能只是 JSON 风格,因为我无论如何都需要更好地处理 JSON — 待定)。 SQLCMD 应该可以与您可以使用的几乎任何版本的 Informix (ESQL/C) 一起编译。

关于sql - 如何防止从 Informix 存储过程返回的长文本值中出现换行符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55874741/

相关文章:

sql - mysql语句无法更新添加4年

sql - Hibernate 创建标准两次连接同一个表 - 尝试了 2 种方法,但有 2 个差异错误

mysql - 连接mysql数据库中的三个表

SQL:编写条件以在变量可能为空时检查变量值的最佳方法

sql - Erlang ODBC 连接挑战

sql - 创建返回文本数组的函数

SQL计算无工作天数

php - mysql 的高级多重连接

php - 准备好的语句与存储过程

postgresql - 在 Postgres 存储过程中传递表值参数