| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3288 人关注过本帖
标题:left()函数在VFP FOR与VFP+SQL查询中使用结果为何不同?
只看楼主 加入收藏
whinda
Rank: 6Rank: 6
等 级:贵宾
威 望:13
帖 子:253
专家分:418
注 册:2012-2-4
收藏
得分:0 
至于
brow * for left(xm,1)="周"就等效于browse * for chr(0)="周"当然没有符合的记录
对于:sele * from alias() where left(xm,1)="周",那是由于比较的处理的结果,
VFP中对SQL唯一有影响的设置是 SET ANSI ON/OFF
select * from alias() where left(xm,1)="周",这里的比较VFP是没有参与的,它交给SQL-SELECT在处理而不是VFP本身。SQL-SELECT不是VFP自带的,是对结构化查询语言的扩展。
select * from alias() where left(xm,1)=="周",你是找不到结果的。
2013-08-23 11:29
sylknb
Rank: 4
等 级:贵宾
威 望:14
帖 子:1547
专家分:184
注 册:2006-6-3
收藏
得分:0 
太深奥了。
2013-08-23 11:34
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:0 
    我在9.0中测试了下:“BROWSE FOR LEFT(姓名,1)=[周]”确实出来的是空窗口(但不报错);“[周]=LEFT(姓名,1)”、“[周]=LEFT(姓名,2)”或反之,都可以;当LEFT()截取的位数>2时,又查询不出了。这种情况是符合8楼分析的,也是FoxPro自身的规则;测试“SELECT 姓名 FROM T1 WHERE LEFT(姓名,1)=[周]”时,查询窗口给出了结果,而且无论是“[周]=LEFT()”还是反之,都可以出相同的结果(LEFT()函数截取任意位数)。又试了下9楼说的情况:“SELECT 姓名 FROM T1 WHERE LEFT(姓名,1)=[州]”时(注意:不是“周”),会出正确结果;但当LEFT()函数截取2位或以上位数的字符时,查询就变成了空记录。这个实验说明,FoxPro的SELECT-SQL命令是从SQL规范中移植过来的,其比较规则与FoxPro本身定义的有些不同。
    根据实验,我猜测,SQL命令是严格按位置比较机内码,而不管你字符串常量中是什么字符。它首先在两边截取第一字节比较,然后再往右,直到两边中字符较少的那个字串取完,给出结果。那么,ASC(LEFT(姓名,1))=ASC(LEFT([周],1))=214,而字串[州]的第1字节机内码(即ASCII码)也是214。同时,等号左边因为只有一个字节,已取完,所以当前比较结果就是整个表达式的比较结果,于是,SQL命令认为LEFT([周],1)=[州]。再看BROWSE命令,由于它采用了FoxPro 9.0自身的规则来比较,所以就不同了。FoxPro 9.0对于“=”的自身规则是:首先比较等号两边的字串长度,如果右边的长度小于等于左边,再开始逐位比机内码大小,然后的过程就与SQL命令的一样。若右边长度大于左边长度,直接就判定不等于,而不管它们的前几字节机内码是否相等。各位可以试试:“BROWSE FOR LEFT(姓名,1)=LEFT([州],1)”或“BROWSE FOR LEFT(姓名,1)=[]”,前者一定会出来姓名字段的第一字节机内码是214的所有记录,而后者一定会出来所有记录。原理就是我上面说的,第一条命令等号两边长度相等,第二条命令等号右边长度小于左边的,所以这两条命令有了比较机内码大小的机会。
    这个实验可以解答楼主的疑惑了。
2013-08-23 12:00
sylknb
Rank: 4
等 级:贵宾
威 望:14
帖 子:1547
专家分:184
注 册:2006-6-3
收藏
得分:0 
sele * from alias() where left(xm,1)="周"的结果
图片附件: 游客没有浏览图片的权限,请 登录注册

sele * from alias() where left(xm,2)="周"结果
图片附件: 游客没有浏览图片的权限,请 登录注册

sele * from alias() where left(xm,3)="周"结果

图片附件: 游客没有浏览图片的权限,请 登录注册


[ 本帖最后由 sylknb 于 2013-8-23 12:10 编辑 ]
2013-08-23 12:06
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:0 
以下是引用sylknb在2013-8-23 12:06:50的发言:

sele * from alias() where left(xm,1)="周"的结果

sele * from alias() where left(xm,2)="周"结果

sele * from alias() where left(xm,3)="周"结果
我上面不是说了嘛,根据实验,LEFT(XM,3)=[周]和LEFT(XM,2)=[周]是一样的结果。因为“周”字只有两个字节,你LEFT()函数取再多字符也就只比较前两位呀。
2013-08-23 12:16
whinda
Rank: 6Rank: 6
等 级:贵宾
威 望:13
帖 子:253
专家分:418
注 册:2012-2-4
收藏
得分:0 
给你说明白了,单字节比较的时候,VFP-SQL会用内码比较,多字节比较时大于ASCII大于129的(129-254)全部当空处理,就是chr(0)。
1.SQL中单字节比较,按内码处理
在SQL中比较时,left("周",1)=left("秦",1),周(内码55004,单字节表示第一字节214,第二字节220),秦(51160,第一字节199,第二字节216),这儿比较的是chr(214)和chr(199)当然不等,如果是?left("周",1)=left("州",1),第一字节都是214,当然相等。

2.SQL中多字节比较,同VFP的比较方式。
?left("周三",3)=?left("周四",3),都取三字节,第三字节被当作chr(0)处理掉了。也就是说“三”(51453)的第一字节200和“四”(52164)的第一字节203都被当作chr(0)处理了,当作空处理了。

在VFP中(不是在SQL中):不管单节还是多字节凡ASCII大于129,都作空处理。
ASCII大于129的(129-254)全部当空处理,就是chr(0)
chr(0)=chr(129)=chr(130)=chr(131)......=chr(254),全部成立。
你可以试一下。

[ 本帖最后由 whinda 于 2013-8-23 13:02 编辑 ]
2013-08-23 12:53
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:0 
以下是引用whinda在2013-8-23 12:53:21的发言:

给你说明白了,单字节比较的时候,VFP-SQL会用内码比较,多字节比较时大于ASCII大于129的(129-254)全部当空处理,就是chr(0)。
1.SQL中单字节比较,按内码处理
在SQL中比较时,left("周",1)=left("秦",1),周(内码55004,单字节表示第一字节214,第二字节220),秦(51160,第一字节199,第二字节216),这儿比较的是chr(214)和chr(199)当然不等,如果是?left("周",1)=left("州",1),第一字节都是214,当然相等。
 
2.SQL中多字节比较,同VFP的比较方式。
?left("周三",3)=?left("周四",3),都取三字节,第三字节被当作chr(0)处理掉了。也就是说“三”(51453)的第一字节200和“四”(52164)的第一字节203都被当作chr(0)处理了,当作空处理了。
 
在VFP中(不是在SQL中):不管单节还是多字节凡ASCII大于129,都作空处理。
ASCII大于129的(129-254)全部当空处理,就是chr(0)
chr(0)=chr(129)=chr(130)=chr(131)......=chr(254),全部成立。
你可以试一下。
亲,你说得不全对哦。CHR(129)=CHR(130)=...=CHR(254),但它们都不等于CHR(0)。有图有真相,可以一条条命令和输出对照起来看。
图片附件: 游客没有浏览图片的权限,请 登录注册

2013-08-23 13:48
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:4 
我觉得这个议题很好,弄清楚了可以避免一些莫名的问题。建议含中文的字串用LEFTC()、RIGHTC()、SUBSTRC()、LENC()等专门针对中文的函数来处理,以免造成查询结果的不准确。
2013-08-23 14:06
sylknb
Rank: 4
等 级:贵宾
威 望:14
帖 子:1547
专家分:184
注 册:2006-6-3
收藏
得分:0 
各位可以试试:“BROWSE FOR LEFT(姓名,1)=LEFT([州],1)”或“BROWSE FOR LEFT(姓名,1)=[]”,前者一定会出来姓名字段的第一字节机内码是214的所有记录,而后者一定会出来所有记录。原理就是我上面说的,第一条命令等号两边长度相等,第二条命令等号右边长度小于左边的,所以这两条命令有了比较机内码大小的机会。
你指的哪二条命令?
2013-08-23 14:20
sylknb
Rank: 4
等 级:贵宾
威 望:14
帖 子:1547
专家分:184
注 册:2006-6-3
收藏
得分:0 
再看BROWSE命令,由于它采用了FoxPro 9.0自身的规则来比较,所以就不同了。FoxPro 9.0对于“=”的自身规则是:首先比较等号两边的字串长度,如果右边的长度小于等于左边,再开始逐位比机内码大小,然后的过程就与SQL命令的一样。若右边长度大于左边长度,直接就判定不等于,而不管它们的前几字节机内码是否相等。各位可以试试:“BROWSE FOR LEFT(姓名,1)=LEFT([州],1)”或“BROWSE FOR LEFT(姓名,1)=[]”,前者一定会出来姓名字段的第一字节机内码是214的所有记录,而后者一定会出来所有记录。原理就是我上面说的,第一条命令等号两边长度相等,第二条命令等号右边长度小于左边的,所以这两条命令有了比较机内码大小的机会。
taifu945:
你说的哪二条命令?
我以下和命令是不是你说的?实验如下:

brow for left(xm,1)=left('州',1),=左,右长度相等,全部记录出来
图片附件: 游客没有浏览图片的权限,请 登录注册

brow for left(xm,1)=left('州',2)=右长度>左长度
图片附件: 游客没有浏览图片的权限,请 登录注册

BROWSE FOR LEFT(xm,1)=[],=左长度>右长度 全部记录出来了
图片附件: 游客没有浏览图片的权限,请 登录注册

2013-08-23 14:47
快速回复:left()函数在VFP FOR与VFP+SQL查询中使用结果为何不同?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.025027 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved