为什么这个 IF FOUND 的条件总是为真?

Why does this IF FOUND have a condition that is always true?

FoxPro7

注意:“记录集”这个词可能不正确,但我真的不明白它们是如何工作的。我是 SQL 人,所以我正在尝试翻译。是一种观点吗?它是数据的副本吗?我不知道。

问题:

  1. 如果您使用的是 2 记录集并进行了更改,更改是否会显示在 1 记录集中?也许他们都指向同一个记录集?
  2. IF FOUND 怎么可能是假的?该代码将 table 的子集与完整的 table 进行比较。它应该永远是真的。
  3. DO WHILE是否受SKIP影响?很难判断一旦您开始执行 DO WHILE 记录集是否已修复,或者您是否可以在此过程中弄乱循环中的记录。如果您更改行,我没有掌握记录循环中“您所在的位置”和“您指向的内容”之间的区别。

谢谢!

    Select 1
    Use tblincls    
    
    Select 2
    Use tblincls Again
    Set Filter To CLASS_CODE = '5156'
    Goto Top

    Do While Not Eof()
    
    nagency_code = agency_code
    nindex_no = index_no
    nclass_code = CLASS_CODE
    npys_exp = pys_exp
    namt_exp = amt_exp

    Select 1
    Seek nagency_code + nindex_no + nclass_code
    If Found()
        Replace pys_exp With (pys_exp + npys_exp)
        Select 2
    Else
        Select 2
        Replace CLASS_CODE With '5157'
    Endif
    Select 2
    Skip
    Enddo

    Close Tables All
    Use tblincls Excl
    Delete All For CLASS_CODE = '5156'
    Pack
    Close Tables All

Note: The word "record set" is probably not correct but I really don't understand how they work. I'm a SQL guy so I'm trying to translate. Is it a view? Is it a copy of the data? I have no idea.

根据代码示例,“记录集”很可能是 VFP table(但也可能是视图),它是 VFP 数据库容器 (dbc) 的一部分。我之所以知道这是因为有一个字段名超过了 10 个字符:一个免费的 table 只能有 10 个字符;超过 10 个字符需要 table/view 在 dbc 中。我会用“table”来回答你的问题。

答案:

  1. tblincls table 打开了两次。对 table 所做的任何更改都将反映在两个 select 区域(1 和 2)中。可以把它想象成 2 个用户打开一个共享文件。两者都在处理同一个数据文件。
  2. 如果过滤后的 table (Select 2) 中有数据,
  3. FOUND() 将永远不会为 false。它不一定 always 为真,因为过滤后的文件中可能没有数据,在这种情况下,“If Found()”代码不会被调用.
  4. DO WHILE受SKIP影响:过滤后的table(Select2)每次循环向前移动1条记录。例如,如果 #1 总共有 20 条记录,而 #2(已过滤)有 4 条记录,则您发布的代码会循环遍历 #2(第一、第二、第三、第四)。为 #2 中的 4 条记录中的每一条记录创建变量,并通过查找 (SEEK()) #1 中的记录在 #1 中进行更新。

解释了所有这些之后,看起来好像对 table 所做的所有更新都在最后通过删除所有记录 (CLASS_CODE='5156') 和打包而完全消失了他们。根据此代码段,CLASS_CODE 永远不会设置为“5157”。这没有意义。这个写的不好。它所做的似乎只是删除 CLASS_CODE='5156'.

的记录

Ed 已经解释得很好恕我直言。让我add\expand更:

  1. 记录集是一个广义术语,它可能表示任何记录集(可以是 table、视图、table 值函数、游标...)-就像总的来说 SQL。

Select 1 和 select 2 的意思是,select“工作区”1 和 2。您可能认为这些数字是唯一的连接句柄。您可以使用关键字“AGAIN”在多个工作区中打开相同的 table\view(或光标...)。第一个使用与 table 名称相同的别名(假设 table - 很可能是 table)。第二个受 VFP 支配并分配了一个自动别名。别名只是 SQL.

中的本地别名

是的,它们是指向同一个 table 的 2 个连接。

  1. 您可能完全正确。但是,使用现有代码,它甚至无法工作并导致错误。如果你真的有这段代码并且它是 运行,那么前面有一些代码可以消除错误。这段代码真正发生的是:

SEEK ... 行出错 我相信错误会被一些前面的代码消除 由于沉默,FOUND() 始终为 FALSE,当前过滤的数据被替换为“5157”并跳到下一条记录。

如果 SEEK 不会出错,仍然不能保证匹配并且 FOUND() 可能为假,因为: SEEK 对当前索引进行操作。当前索引可能与以下搜索不匹配:

agency_code + index_no + class_code

WORSE,数据类型在此代码中未知,这些变量以 'n' all 为前缀,这可能意味着它们是数字,那么这将是 3 个数字字段的总和,而不是串联3 个字符字段。即:

agency_code = 1 index_no = 1 class_code = 1

然后搜索将意味着:

寻找 3

但是,我们已经知道CLASS_CODE是一个字符串,其他的也应该是字符串(或者是另一个错误)。

  1. Do While 只关心它的逻辑表达式部分。在此代码中,它仅检查它是否为 EOF()。 EOF() 表示“当前 table\view\cursor”的文件结尾。因为只是在 ENDDO 之前命中,它正在执行 SELECT 2,这意味着循环将继续,直到在工作区 2 中命中 EOF(由 CLASS_CODE='5156' 过滤)。由于代码中没有任何其他内容在任何 table 中移动指针,因此它是工作区 2 中记录的一次传递(就 SQL 服务器而言,您为 [=62 声明了一个游标=] with CLASS_CODE = '5156',获取下一个直到状态不为 0)。

让我们扩展对代码本身的注释:

* Select workarea 1 - like opening a new connection tab in SSMS to the same database
Select 1
* Open table tblincls in this work area
* it is like allocating a cursor but let's don't make it complex
Use tblincls


* Select workarea 2 - like opening a new connection tab in SSMS to the same database
Select 2
* Open table tblincls in this work area AGAIN with a local alias of (likely  - automatic) B
Use tblincls Again
* Filter this one 
Set Filter To CLASS_CODE = '5156'
Goto Top


* So up to this point it is as if you have 2 cursors allocated
* one with
* Select * from tblincls
* and the other
* Select * from tblincls where CLASS_CODE = '5156'


* Starting a loop using - on work area 2
Do While Not Eof()

* Copy contents of some fields to some memory vairables 
* (The variables on left are all memory variables,
* because in VFP you cannot do assigment to field variables)

    nagency_code = agency_code
    nindex_no = index_no
    nclass_code = CLASS_CODE
    npys_exp = pys_exp
    namt_exp = amt_exp

* Select work area 1
    Select 1
* Call SEEK. Since there is no index set, this would cause an error
* error is likely silenced by some preceding code (or in a TRY block)
* ie: If you had a line like this, code would continue without displaying any error 
* On error x=1 
* A dummy error silencer

    Seek nagency_code + nindex_no + nclass_code

* Always FALSE because of the error

* If index was set and error didn't occur
* and also index expression matches to 
* agency_code + index_no + class_code
* at least, then that would mean always TRUE
* It would find the record itself, or some other row
* Which row it would be is unpredictable (unless that expression is unique)

    If Found()
        Replace pys_exp With (pys_exp + npys_exp)
        Select 2
    Else
        Select 2
        Replace CLASS_CODE With '5157'
    EndIf
    
* Select work area 2 regardless of the above    
    Select 2
* Move the pointer
    Skip
Enddo

* No need to explain rest I guess
Close Tables All
Use tblincls Excl
Delete All For CLASS_CODE = '5156'
Pack
Close Tables All

最重要的是,这是我见过的最糟糕的代码之一。也许我可以把它翻译成 SQL(说 SQL 它可能是任何方言):

Update tblincls Set Class_Code = '5157' where class_code = '5156'

像这样,因为代码归结为这个(我也会在 VFP 中这样写)。