1
FOR EACH loan WHERE /* Condition1 */ loan.date = SomeDate
                AND /* Condition2 */ loan.type = SomeType
                AND /* Condition3 */ (IF SpecMode THEN TRUE ELSE loan.spec = SomeSpec)

当 SpecMode = TRUE 时,Condition3 = TRUE。所以我想知道当 SpecMode = TRUE 时,上面的代码和下面的代码是否会完全相同(包括速度)?

FOR EACH loan WHERE Condition1 
                AND Condition2
                AND TRUE

或者甚至像这样?

FOR EACH loan WHERE Condition1 
                AND Condition2

一般而言,问题是 Progress 如何管理可以评估的条件,而不管数据库记录如何。需要更多时间吗?还可以提供有关 Progress 如何在更深入的视图中工作的链接,我们将不胜感激。


添加 08/16/13:我最初使用的代码是:

IF SpecMode THEN
  FOR EACH loan WHERE Condition1 AND Condition2:
    RUN Proc.
ELSE
  FOR EACH loan WHERE Condition1 AND Condition2 AND Condition3:
    RUN Proc.

动态查询是我想到的第一个想法,但我意识到这意味着用动态查询样式重写所有嵌套代码(这是 imo 的可读性更差,我将其移至单独的问题)。我想采用现代方法,所以如果它是最合理的解决方案,我会这样做。

第三种方法可以使代码保持“静态样式”。它使用带参数的包含文件。但这意味着.i已经庞大的代码库中的另一个文件。而且我通常讨厌这种方法(以及使用包含代码的预处理器常量“作弊”)。我们的系统又大又旧,到处都是这种东西,很难分析,基本上看起来就是不对的。

4

5 回答 5

3

嵌入在 WHERE 子句中的 ( IF ... THEN ... ELSE ... ) 被视为一个函数。

一般来说,最好避免在 WHERE 子句中调用函数。有些(但不是全部)可以在服务器端解决。(用户定义函数和 CAN-DO() 是必须在客户端上评估的两个示例。)

在你的情况下,我不知道 IF 总是正确的。如果 specMode 为真,则为真,但如果为假,则评估 ELSE 部分,如果不查看数据,我无法知道结果如何。因此,按照您的建议替换它不一定是正确的。

如果 specMode始终为真,那么,是的,按照您的建议替换它(两个版本)都可以。

从效率的角度来看,使用 IF 函数消除了在 loan.spec 字段上加括号的能力。如果loan.date 和loan.type 是索引的主要组成部分,那么它们将用于括号。但是,如果 loan.spec 也是一个索引组件,则它不能用于改进选择,并且需要单独检查由其他标准划分的整个记录​​子集。

我认为您显示的代码可能被用来提供一个“聪明”的选项,可以显示带有日期和类型的所有记录,或者只是日期、类型和规范的子集。在过去,这可能是一种有吸引力(但难以阅读且效率低下)的方法。它将允许单个代码块处理循环体内的任何内容。

在当今世界,您不需要这样做。您只需编写一个动态查询并将一个适当的 WHERE 子句填充为一个字符串,然后在该字符串上使用 QUERY-PREPARE。这样,如果loan.spec 是索引的一部分,它可以用来帮助支持查询,并且这些案例将运行更快。

于 2013-08-15T16:23:07.340 回答
2

作为 Toms 出色答案的插件,一个提示是在您不确定使用什么索引时使用外部参照进行编译。

COMPILE file.p [SAVE] XREF file.txt.

这将生成一个包含索引使用情况的文件(除其他外)。寻找这样的行:

c:\temp\program.p c:\temp\include.i 21 SEARCH db.webkonv tkn WHOLE-INDEX

SEARCH 表示在此示例中使用了表“webkonv”的索引“tkn”。WHOLE-INDEX 表示整个索引已被扫描(在这种情况下,这是预期的 - 此代码在 TABLE-SCAN 指令之前使用)。检查 COMPILE 语句上的 ABL 参考。

于 2013-08-16T07:43:06.053 回答
1

对于您的情况:

EACH loan WHERE /* Condition1 */ loan.date = SomeDate
        AND /* Condition2 */ loan.type = SomeType
        AND /* Condition3 */ (IF SpecMode THEN TRUE ELSE loan.spec = SomeSpec)

你可以这样尝试:

your_loop:
EACH loan WHERE /* Condition1 */ loan.date = SomeDate
    AND         /* Condition2 */ loan.type = SomeType
    : 
    /* Condition3 */ 
    IF not SpecMode THEN DO:
        If loan.spec <> SomeSpec THEN
            NEXT your_loop. /* both false, next loop */
    END.

    /* ........ do your work ...... */

END. 
于 2013-08-30T01:46:12.057 回答
1

我看不出使用 a for each 没有任何意义,没有提到表的任何字段......无论条件是真还是假,都会选择整个表,因为没有对表的查询。

在任何情况下,Progress 都会评估完整条件并检索与该条件匹配的记录集。

示例 1。

def var 作为逻辑初始化假。

对于每个项目,其中:

显示item.code。/* 将不显示任何内容,但会读取表的所有记录 */

结尾。

示例 2:

def var a as 逻辑初始化为真。

对于每个项目,其中:

  display item.code.    /* Will display all records of the table */

结尾。

示例 3:

定义变量 v_user_can_read_items init false。

对于 item.code 以“4”开头的每个项目和

                v_user_can_read_items = true:


 display item.code.  /* will display nothing but read all items starting by 4 */

结尾。

花费的时间将取决于 where 条件,前两种情况会很慢,因为正在读取所有记录。在第三种情况下会很快,因为首先选择从 4 开始的项目集,然后不显示,因为条件返回 false。

最短的时间是何时使用适当的索引(条件使用)并且检索到的集合是一组短数据。

于 2013-08-30T14:58:45.010 回答
-1

定义变量 v_user_can_read_items init false。

对于 item.code 以“4”开头的每个项目和

            v_user_can_read_items = true:

显示item.code。/* 将不显示任何内容,但会读取从 4 开始的所有项目 */

结尾。

于 2014-04-24T12:36:37.017 回答