在 INFORMIX 4GL 的报告中对“ORDER BY”使用“IF 语句”

Posted

技术标签:

【中文标题】在 INFORMIX 4GL 的报告中对“ORDER BY”使用“IF 语句”【英文标题】:Use an "IF statement" on the "ORDER BY" in a report in INFORMIX 4GL 【发布时间】:2016-09-07 18:39:04 【问题描述】:

我有一份被多次调用的报告,但我希望每次的顺序都不同。

如何根据变量更改“排序依据”。

例如

report print_label()

   If is_reprint
   then
       order by rpt.item_code, rpt.description
   else
       order by rpt.description, rpt.item_code
   end if

我尝试在调用报表时传入一个变量:

let scratch = "rpt.item_code, rpt.description"
start print_label(scratch)

在我所做的报告中:

order by scratch

但它没有用......还有其他建议吗? 谢谢!

【问题讨论】:

【参考方案1】:

我用来解决这类问题的技术类似于

REPORT report_name(x)
DEFINE x RECORD
    param1,param2, ..., paramN ...,
    sort_method ...,
    data ...
END RECORD

ORDER [EXTERNAL] BY x.param1, x.param2, ..., x.paramN

BEFORE GROUP OF x.param1
    CASE 
        WHEN x.sort_method ...
            PRINT ...
        WHEN x.sort_method ...
            PRINT ...
    END CASE

BEFORE GROUP OF x.param2
    # similar technique as above

...

BEFORE GROUP OF x.paramN
    # similar technique as above

ON EVERY ROW
    PRINT ...

AFTER GROUP OF x.paramN
   # similar technique as above
...

AFTER GROUP OF x.param2
    # similar technique as above

AFTER GROUP OF x.param1
    # similar technique as above

...然后在调用 REPORT 的 4gl 中,使用用于排序的所需参数填充 x.param1、x.param2、...、x.paramN,例如

CASE x.sort_method 
    WHEN "product,branch"
        LET x.param1 = x.data.product_code
        LET x.param2 = x.data.branch_code
    WHEN "branch,product"
        LET x.param1 = x.data.branch_code
        LET x.param2 = x.data.product_code
END CASE
OUTPUT TO REPORT report_name(x.*)

因此,根据我的示例,这是一种我已经看到并用于股票报告之类的技术。仓库/分支/商店经理希望查看按仓库/分支/商店订购的东西,然后是产品/sku/item,而产品经理希望查看按产品/sku/item 订购的东西,然后是仓库/分支/店铺。可以使用相同的技术完成更多具有更多潜在参数的分析报告。我认为我看到的记录是 6。因此,在这种情况下,一份报告涵盖所有 6!=720 个潜在组合要好得多,而不是为每个可能的订单组合编写单独的报告。

因此可能类似于 Jonathan 选项 1,尽管我对复杂性没有相同的保留。我不记得在代码审查中发现我的任何初级开发人员都犯了严重错误。事实上,如果报告足够通用,您会发现不需要太频繁地触摸它。

【讨论】:

【参考方案2】:

简答

I4GL REPORT 函数中的 ORDER BY 子句对如何生成实现报告的代码具有至关重要的影响。像在运行时那样重新连接生成的代码是不可行的。

因此,你不能直接达到你想要的结果。

注意事项

请注意,您可能应该使用ORDER EXTERNAL BY 而不是ORDER BY — 不同之处在于,使用EXTERNAL,报告可以假设数据以正确的顺序显示,但如果没有,报告必须保存所有数据(在数据库中的临时表中),然后从表中按要求的排序顺序选择数据,制成两遍报告。

如果您有勇气并拥有 I4GL c 代码编译器,您应该查看为报告生成的代码,但请注意,这是您很可能会在很长一段时间内遇到的最可怕的代码.它使用了你自己做梦也想不到的各种技巧。

解决方案——概述

好的;所以你可以直接做。你有什么选择?在我看来,你有两个选择:

    使用两个参数专门用于选择排序,然后使用 ORDER BY(不带EXTERNAL)子句始终按固定顺序列出它们。但是,当需要使用报告时,请选择您希望参数使用的顺序。

    编写两个仅报告名称和 ORDER EXTERNAL BY 子句不同的报告。根据您想要的顺序安排调用正确的报告。

其中,选项 2 更为简单——除了维护问题。最有可能的是,您会安排从单个副本生成代码。也就是说,您将REPORT print_label_code_desc 保存在一个文件中,然后安排将其编辑为REPORT print_label_desc_code(例如,使用sed)——并且编辑将反转ORDER BY 子句中名称的顺序。这在makefile 中并不难做到,尽管它需要一些小心。

实践中的选项 1

选项 1 在实践中是什么样的?

DECLARE c CURSOR FOR
    SELECT * FROM SomeTable

START REPORT print_label -- optional specification of destination, etc.

FOREACH c INTO rpt.*
    IF do_item_desc THEN
        OUTPUT TO REPORT print_label(rpt.item_code, rpt.description, rpt.*)
    ELSE
        OUTPUT TO REPORT print_label(rpt.description, rpt.item_code, rpt.*)
    END IF
END FOREACH

FINISH REPORT print_label

报告函数本身可能如下所示:

REPORT print_label(col1, col2, rpt)
    DEFINE col1 CHAR(40)
    DEFINE col2 CHAR(40)
    DEFINE rpt  RECORD LIKE SomeTable.*

    ORDER BY col1, col2

FORMAT

    FIRST PAGE HEADER
        …
    BEFORE GROUP OF col1
        …
    BEFORE GROUP OF col2
        …
    ON EVERY ROW
        …
    AFTER GROUP OF col1
        …
    AFTER GROUP OF col2
        …
    ON LAST ROW
        …
END REPORT

对于大纲代码中的任何错误,我们深表歉意;距离我上次编写任何 I4GL 代码已经有一段时间了。

关键点是 order by 值是专门传递给报表的,并且仅用于控制其组织。你可能需要 能够在两列的 BGO(BEFORE GROUP OF 的简写;AGO 为 AFTER GROUP OF)部分打印不同的详细信息。这通常由(喘气的)全局变量处理——这是 I4GL,它们是做生意的正常方式。实际上,如果报告驱动程序代码(调用 START REPORT、OUTPUT TO REPORT 和 FINISH REPORT 的代码)与报告本身位于同一文件中,则它们应该是模块变量而不是全局变量。您需要这个,因为通常在组级别(在 BGO 和 AGO 块中)的报告将需要不同的标题或标签,具体取决于您是否在描述之前对代码进行排序,反之亦然。请注意,组聚合的含义会根据 ORDER BY 子句中的顺序而变化。

请注意,并非每份报告都必然适合这种重新排序。仅以不同的顺序运行 BGO 和 AGO 块不足以使报告输出看起来合理。在这种情况下,您将退回到选项 2 — 或选项 2A,即编写两个单独的报告,它们不会假装只是对 ORDER BY 子句的重新排序,因为数据的格式需要根据不同的ORDER BY 子句。

如您所见,这需要一些小心 — 比替代方案(选项 2)要更加小心。如果您使用动态 SQL 创建 SELECT 语句,您可以安排将正确的 ORDER BY 子句放入准备好的字符串中,以便游标以正确的顺序获取数据——毕竟允许您使用 ORDER EXTERNAL BY .

总结

如果您是 I4GL 的新手,请选择选项 2。如果您的团队在 I4GL 方面经验不足,请选择选项 2。我不太喜欢它,但这是可以处理的方式您自己、您当前的同事以及未来的同事都容易理解并且容易理解。

如果您对 I4GL 相当满意,并且您的团队对 I4GL 有相当的经验 - 并且报表布局确实适合动态重组 - 然后考虑选项 1。它比较棘手,但我在 I4GL 中做了更糟糕的事情在过去。

【讨论】:

谢谢乔纳森。我之前尝试过选项 1,但它不起作用。我收到以下错误:“报告中指定的 ORDER BY 或 GROUP 项必须是报告参数之一。请参阅错误号 -4415。) 在这种情况下,你需要使用选项 2。我可以肯定选项 1 可以工作,但它远非微不足道,不一定会给你比无论如何选择2。根据我的经验,选项 2(或 2A)可能是满足报表数据布局的业务要求所需的选项。 我想这是我现在唯一的选择,我尽量避免写另一份报告,因为它是一份大报告,未来所有的修改都必须对这两份报告进行。 整数与字符串。对于字符串,“100”排在“29”之前,但不是数字。你需要考虑什么是最好的。您有一个整数(项目代码)和一个字符串(项目描述)IIRC,这意味着您不能同时生成这两个整数。这意味着您可能需要格式化数字右对齐(或在左侧填充零),以便正确比较字符串。例如,0000000100 和 0000000020 作为字符串和数字正确排序。使用空格代替前导零也可以。 (我希望我的计数是正确的!)。 您应该能够控制它,因为col1col2 值完全在您的控制之下。它们不必是记录中基础值的直接副本;您可以针对不同的类型对它们进行不同的映射。重要的是,报告强加的 alpha 排序将数据按正确的顺序排列——无论需要什么狡猾的技巧。我知道我的示例代码显示逐字传递记录中的列(除了整数将在内部转换为字符串),但那是我做的或多或少必要工作的最低限度。【参考方案3】:

您可以在 order by 子句中使用 case 语句,如下所示:

order by 
       case 
         when 1 = 1 then 
            rpt.item_code, rpt.description
         else
            rpt.description, rpt.item_code
       end

【讨论】:

不,很抱歉,但这与 I4GL 报告中的 ORDER BY 子句没有密切关系——这正是这个问题所要问的。 I4GL 报告中的 ORDER BY 子句不是 SELECT 语句的一部分,甚至 - 它是数据如何呈现给报告的规范,它控制如何使用报告中的代码,因此控制了 C 代码为 I4GL c 代码编译器生成(以及 I4GL p 代码编译器的相应 p 代码)。【参考方案4】:

你可以使用准备:

let query_txt="select ... "
If is_reprint then
  let query_txt=query_txt clipped, " order by rpt.item_code, 
  rpt.description"
else
  let query_txt=query_txt clipped, " order by rpt.description, 
  rpt.item_code"
end if
prepare statement1 from query_txt
declare cursor_name cursor for statement1

现在开始报告,使用 foreach 等...

附:您必须将 query_txt 定义为足够长的字符以容纳整个文本。

【讨论】:

以上是关于在 INFORMIX 4GL 的报告中对“ORDER BY”使用“IF 语句”的主要内容,如果未能解决你的问题,请参考以下文章

下午在 Informix 4GL 中显示

在 Informix 4GL 程序中验证 URL

如何在 Informix 4gl 中引用 TEXT 类型?

在 informix 中捕获错误

无法运行 Informix 4GL 交互式调试器

在 4GL Informix 中关闭“Wy-60”?