以下是引用liuxingang28在2014-2-14 17:00:48的发言:
闲暇之余,花了二天时间认真阅读了该书。总体来说,该书还不错,读后有不少收获,但也发现了几处不足或错误,如下:
1. 第15页,作者建议“字符型数据全部使用Varchar型,这样可避免再使用Alltrim()函数消除多余的尾部空格”。根据本人的开发体验,在VFP下Varchar型并不比Character有优势。一是Varchar并不比Character节省空间,二是Varchar仍然会存储手工录入的空格。VFP提供该字段类型只是为了兼容SQL Server。
2. 第22页,作者建议在命令窗口中输入较长命令时,在行尾输入分号号后按Ctrl_Enter来换行,不能直接按回车。但经上机验证,直接回车也可以。
3. 第38页,在介绍REPLACE命令时,作者认为“有 FOR/WHILE短语时,默认范围是ALL”,应该纠正为:有FOR短语时,默认范围是ALL,有WHILE短语时默认范围是REST,同时有FOR短语和WHILE短语时,默认范围是REST,即WHILE优先。
4. 第42页例3,“skip 记录号-RECNO()”有错误。比如,当前记录号是8,要切换到记录号3时,skip 3-8 则将记录切换到了第2条记录,显然错误。应该修改为:
go 记录号
if dele()
skip
if eof() and !bof()
skip -1
endif
endif
5. 第74页,关于掩码“9”的作用,作者表述为“只允许输入数字和+-号”,应纠正为“对字符号字段只允许输入数字”,对于数值型字段只允许输入数字和+-号”。
6. 第111页例3,其中的“having avg(英语)>=85”改为“having 英语平均分>=85”更好一些
7. 第142页,其中的“where ... and 成绩=(select ...)”改为“where ... and 成绩 in (select ...)”更好一些,因为若子查询若回多条记录时,程序会出错,使用 in 则不会。
8. SQL的例子中,一个查询语句中出现多个子查询,甚至出现重复的子查询,使程序的可读性很差。其实,在编写SQL语句时,先将子查询输出到一个游标,再对游标进行操作,有时也很好,特别是需要重复引用子查询中的记录时。
9. 第168页第2行,在介绍Between函数时,作者表述为“该函数不区分大小写”,这个表述是错误的。只所以between('B','a','C')返回.f.,是因为Set Collate to "PinYin"引起的,输入Set Collate to "Machine"后,返回.t.。在PinYin排序方式下,不是按字符的Ascii码值进行比较的,而是按其拼音的先后比较,这可能与我们的习惯不同。
10.第196页倒数第6行,在介绍EndScan时,作者专门强调“在Endscan前切换到原工作区”。其实,根本没有必要,在执行Endscan时系统会自动切换到原工作区。
11.第208页倒数第7行中的“skip -reccount()”语句令人费解,应该改为“go top”更容易理解。
12.第247页,第1行,将“THISFORM.backcolor.value=255+255*256+0*65536”改为“thisform.backcolor.value=rgb(255,255,0)”更简单。
13.第268页,在记录导航条的代码中有大量的重复代码,使用算定义方法可能更好。
14.第283页,将Dakai.Click中使用低级文件函数读出文本文件内容的语句改为:THISFORM.源文本区.Value = FileToStr(文件名)。
15.第293页第4行开始的代码段有问题:若备选列表允许多选,则其中的“THISFORM.已选.additem(this.value)”应改为“THISFORM.已选.additem(this.list(i))”;若备选列表不允许多选,则仅需先清除已选列表,再执行“THISFORM.已选.additem(this.value)”一条语句即可。
……
还有很多,由于时间的关系我要下班回家了!
非常感谢你的意见。之所以回复你比较晚,是因为再次对你提出的质疑进行了一一验证,现答复如下:
1、Varchar对于Character的优势并不在于节省空间(这点我在书中也提到了,并介绍了该类型存储的原理),而在于编程时的便捷性,不用考虑字符型的后面是否填充有空格。我个人认为,用可变长字符串的优势在于编程时可少一层考虑,不用担心因为字符串后面无谓的空格而影响程序走向;
2、确实如你所说,直接按回车也可以;
3、经我再次验证:REPLACE...WHILE的默认范围确为REST;同时存在FOR,WHILE两个短语时,以WHILE优先;
4、这个例子经我再一次反复测试,结论与之前一样。你可以打开一个表文件,定位到第8条记录,再用SKIP 3-8,看看是否能回到第3条记录(第3-8条记录没有被删除时)。另外,我这个例子是为了展示如何让指针不误指到已被删除的记录上,不是为了展示SKIP可以比GO更精确地定位记录。所以,这个例子是放在删除记录的小节里介绍的;
5、正如你所说,对于C、V型字段,只允许输入数字;数值型或其兼容型字段允许输入数字和正负号;
6、两种方法是一样的,我个人认为习惯哪种就用哪种;
7、子查询的输出项用了聚集函数MAX(),在没有分组的情况下只可能输出一个数值,不可能有第二个。你可以再仔细斟酌一下,是不是这样;
8、你说得不错,我也是这样认为的。但在不影响可读性的情况下,适当使用子查询也不是不可以。这点,在我子查询介绍的第6点“关于子查询的小结”中已经有指出;
9、经你提醒,我又反复实验了一下:在SET COLLATE TO 'pinyin'/'Stroke'时,BETWEEN()函数不区分大小写,而在SET COLLATE TO 'machine'时区分大小写;
10、确如你所说,ENDSCAN会自动识别配套的SCAN属于哪个表文件;
11、与第6点一样,两种方法都可以的,看个人习惯,我个人习惯用SKIP。还有,这段程序可以用上面黄色背景的一条UPDATE-SQL搞定,写这段代码只是为了对比SQL命令和普通命令;
12、对于RGB()函数,后文已有介绍;
13、不知道你所说的“算定义方法”是什么。这个例子我在发布前也经多次测试,如果四个记录导航按钮不重复写这些代码,光靠一句表单刷新,是不会改变表单显示内容的。这一点,我刚刚又重新测试了一下,确实应该“重复”这些代码;
14、用FILETOSTR()函数读入文本文件确实比低级函数方便。由于以前没用过该函数,因此写本书的时候没想到它;
15、你说的那个例子是单选项,不多选,确实可以按你说的方式改进。
最后,再一次感谢你指出这么多问题,尽管有些地方值得再商榷,但还是能看出你这个论坛新人的实力。而且注册了ID后第一帖就给我,太感谢了,希望以后能在论坛中多多见到你的身影,更希望你在百忙之余继续为本书“找茬”。另外,我会根据你提出的建议修正书中一些不妥的内容,然后再次发布出来,让更多的人用好这款经典的桌面数据库软件。