| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4876 人关注过本帖, 1 人收藏
标题:求助如何将非dbf表(.csv文件)有选择的添加到dbf表里
只看楼主 加入收藏
厨师王德榜
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:199
帖 子:995
专家分:4966
注 册:2013-2-16
收藏
得分:0 
今天好不容易有点时间,那我就接着讲了,下面的内容是当初写的软件说明里粘贴来的,主要是我懒,不想打重复的内容。
我们今天接着讲字段对应表,他的大概格式如图:
图片附件: 游客没有浏览图片的权限,请 登录注册

起作用的列只有5列(其它的列请忽略),这六列分别是:
FIELD_NAME、FIELD_TYPE、FIELD_LEN 、FIELD_DEC、FIELD_DEFA,下面我们分别讲解:
FIELD_NAME ――TXT文件中,表头原来的名字。
FIELD_TYPE ――期望这一列,转换后成为什么格式?用一个大写的英文字母来表示
(按VFP标准,用户通常有以下选择:C、N、I、D、T、L,分别对应:字符型、数值型、整形、日期型、日期时间型、逻辑型),请勿输入其它字符!
FIELD_LEN ――期望这一列,转换后有多大长度?当字段类型为C、N时,此数值有意义。
FIELD_DEC ――期望这一列,转换后的小数位长度?当字段类型为N时,此数值有意义。
FIELD_DEFA――转换后的列名字,可与原列名相同,也可不同,
例如上图中,原列名叫[Tr.prt],转换后,我们希望这列的名字叫[贸易伙伴],
那么就在这一列,写上转换后的名字。再例如:[过帐日期]改为[过账日期]等等。

注意事项1:请遵守VFP规范,VFP不允许数字开头的列名,如“2013收入”,也不允许-~@%&<>/\?* 等怪异字符。
注意事项2:FIELD_DEFA列可以为空,为空,表示这一列,程序放弃转换。



[此贴子已经被作者于2018-1-29 15:29编辑过]

2018-01-29 14:45
厨师王德榜
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:199
帖 子:995
专家分:4966
注 册:2013-2-16
收藏
得分:0 
有了这个对应表,程序就像有了演出剧本,他的作用很快我们会讲。
接下来程序会开始处理这个装入了文本文件的表,那么算法如何设计呢?
首先,程序会从表的第一行开始判断这一行是不是表头,如不是,再判断下一行。。。直到找到表头。

我们怎么判断某一行是不是表头呢?

比如上图的示例,原表有10多列,如果我们在表的某行能否同时找到:公司、科目、供应商、客户。。。等10个完全相同的字串,
我们就可以认为,这一行就是表头了,反之,如果这一行虽然有个别字串符合:公司、科目、供应商、客户。。。但是符合的数字未达到10,
我们就认为这一行不是表头。这个数字10可以由用户根据这个文件本身的特点来定的,如果是其它表,当然这个值也要变化的。

但是我们还要考虑程序的运行效率问题,比如一个很多列(230多列)的表,难道我们需要从某行的第1列,一直找到第230列吗?显然不需要,
仍以上表为例,如果某行我们从第1列找到50列,都没找到足够(10个)符合:公司、科目、供应商、客户。。。的字串,
那么这一行已经可以放弃查找了,并跳到表的下一行开始查找了。


2018-01-29 15:08
厨师王德榜
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:199
帖 子:995
专家分:4966
注 册:2013-2-16
收藏
得分:0 
继续说运行效率的问题,假设某表有20000多行,程序从第一行一直往下找表头,难道需要一直找到末行吗?显然不需要,万一是用户误操作,装入了一个本来就是错误的表呢?程序一直找下去,岂不是做了很多无用功?所以,我们需要再给程序设计一个“刹车”机制,让他判断当找到第N行仍未找到表头时,就放弃查找,弹出对话框提醒用户。

请注意上面红色的值,有了前面的铺垫,现在讲上图的参数就容易理解了:
参数1:首先需要建立一个多少列的表?前面说过,这个值是K这个值由用户根据他要转换的表自行指定,K值必须比文本文件总列数B略大(但必须小于VFP允许的上限254),原因是文本文件的总列数随机有浮动,所以K值一般比B大10~20为宜。
参数2:从某行第1列一直找到第X列时,如仍未找到足够多的符合条件的列,则放弃本行查找,跳到表的下一行继续找。不难判断,这个X的值,只能小于等于K
参数3:在某行中,至少要找到Y个符合名称的列,才判断该行是表头,退出查找,否则不是。不难推断,Y值只能小于等于X
参数4:某个表中,如果从首行一直找到第N行仍未找到表头时,就放弃查找,弹出对话框提醒用户。
参数解释完毕,由于这个参数是开放给用户的,所以必须讲透。这样用户在制作字段对应表时,才能根据实际情况,制定出合理的参数1~4。
图片附件: 游客没有浏览图片的权限,请 登录注册



[此贴子已经被作者于2018-1-29 15:34编辑过]

2018-01-29 15:27
厨师王德榜
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:199
帖 子:995
专家分:4966
注 册:2013-2-16
收藏
得分:0 
有了上述的算法为基础,在制作好字段对应表后,程序的代码就简单了:
(以下只有描述,代码就不写了,以各位的水平,绝对足够写出漂亮的代码了)
找表头,用Fields(i)循环查找,
当某行的值与对应表中的FIELD_NamE 相同时,累加器 +1,
当 累加器 达到参数3时,本行就是表头,否则继续向下一个列循环,
当找到参数2时,仍未找够,则跳到下一行继续找。

当找到第N行(参数4)仍未找到表头时,查找失败,跳出循环,弹出对话框提醒用户。

当找到表头后,就可以对字段对应表进行逐行循环,根据字段对应表定义好的 FIELD_TYPE、FIELD_LEN  、FIELD_DEC、FIELD_DEFA
不难拼凑出合适的 “Alter Table 表 alter column ”语句,把原来的文本列,改为需要的数值型、日期型。。。
特别提示1:由于是从文本中转换,当某列转换为数值时,一定要先把可能含有的逗号去掉。例如文本中是1,234.56 不去掉逗号直接转换的话肯定丢失数据。
特别提示2:当某列转换为日期时,一定要先把当前系统的日期分隔符设置成与文本中一致,不然也会丢失数据。

当然,各位都是有经验的User,这种低级错误想必不会出现。

至此,中间文件生成完毕,再把这个中间文件追加进你原来的,定义好结构的正式表,就达到了只追加指定列的效果。
而且,本算法同时实现了列类型的转换,列的改名,再者由于本算法是从第一行开始找表头,也能适应表头不在首行的情况。

从以上算法的描述可以看出,文本文件的列相对位置变动,我们是能找到办法处理的,因为我们是找某行中各列的值 与字段对应表中相比较,无论他的列位置相互之间如何变动,我们总能把他找出来。

对用户而言:
只需把“字段对应表”的设计看懂,把四个参数的含义弄清楚,制定出合理的参数,就能解决所有类似的问题。

对开发者来说,把以上算法看明白,不难写出漂亮适用的代码。本算法的好处是代码是“活”的,不是“死”代码,
真正需要定制的,只有“字段对应表”。这样一来,把“字段对应表”后期的维护交给用户自己来完成,开发者可以轻松很多。(完)


[此贴子已经被作者于2018-1-29 16:15编辑过]

2018-01-29 15:56
schtg
Rank: 12Rank: 12Rank: 12
来 自:Usa
等 级:贵宾
威 望:67
帖 子:1794
专家分:3418
注 册:2012-2-29
收藏
得分:0 
@厨师王德榜大侠,学习啦,谢谢!
2018-01-30 08:07
yewxj
Rank: 3Rank: 3
等 级:论坛游侠
威 望:5
帖 子:157
专家分:153
注 册:2015-6-18
收藏
得分:0 
@厨师王德榜 学习啦,十分感谢!
2018-01-30 10:44
yewxj
Rank: 3Rank: 3
等 级:论坛游侠
威 望:5
帖 子:157
专家分:153
注 册:2015-6-18
收藏
得分:0 
以下是引用吹水佬在2018-1-26 11:28:52的发言:

规则是必需有“我爱编程论坛aa”和“我爱编程论坛cc”
USE 新表
ZAP
cData = FILETOSTR("分类查询.csv")
nFaa = 0
nFcc = 0
nLines = ALINES(arrData, cData)
IF nLines > 0
    FOR i=1 TO ALINES(arrFields, arrData[1], ",")
        DO CASE
        CASE arrFields=="我爱编程论坛aa"
            nFaa = i
        CASE arrFields=="我爱编程论坛cc"
            nFcc = i
        ENDCASE
    ENDFOR
ENDIF
IF nFaa>0 AND nFcc>0
    FOR i=2 TO nLines
        nFields = ALINES(arrFields, arrData, ",")
        IF nFields>=nFaa AND nFields>=nFcc
            INSERT INTO 新表 VALUES (VAL(arrFields[nFaa]), VAL(arrFields[nFcc]))
        ENDIF
    ENDFOR
ENDIF
BROWSE


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

根据水版的语句,为了更方便的增减使用的字段,我也做了类似 厨师王德榜 老师的字段对比表,有128个字段,因为程序调用字段是不固定的(根据字段表 是否启用 字段来判断),所以不能使用水版的“INSERT INTO 新表 VALUES (VAL(arrFields[nFaa]), VAL(arrFields[nFcc]))”插入,我做的是非常笨拙的循环添加,效率特别低,请问各位老师有更优方案吗?

CLOSE ALL

_bst="分类查询"+LEFT(ALLTRIM(DTOS(DATE())),4)+"-"+LEFT(DTOC(DATE()),2)+"-"+SUBSTR(ALLTRIM(DTOC(DATE())),4,2)+".csv"
_cData = FILETOSTR(_bst)
_nLines = ALINES(arrData, _cData)
ALINES(arrFields, arrData[2], ",")

*-*创建空表并添加字段
_bstfile="数据_"+DTOS(DATE())
CREATE dbf &_bstfile (序号 N(8))
USE 字段库 ALIAS 字段库 IN 0
SELECT 字段库
GOTO TOP
DO WHILE !EOF()
    IF LEN(ALLTRIM(程序字段)) > 0 AND 是否启用 = "是"
        _fN = 程序字段
        _fT = 字段类型
        ALTER TABLE &_bstfile ADD &_fN &_fT
    ENDIF
    SKIP
ENDDO

*-*向空表中添加数据
SELECT &_bstfile
FOR i=2 TO _nLines                        &&循环所有来源数据行
    APPEND BLANK                          &&添加空白记录
    REPLACE (FIELD(1)) WITH i-1           &&第一个字段添加序号
    ALINES(arrFields, arrData[i], ",")    &&将数据的i行 复制到数组arrFields
    FOR _bstList=2 TO FCOUNT()            &&循环字段数减去之前增加的序号字段
        _ZD=FIELD(_bstList)               &&将当前字段名复制到变量_ZD
        SELECT 字段库                     
        LOCATE FOR 程序字段=_ZD           &&指针指向 字段库 程序字段 = _ZD 的记录
        _XH=序号                          &&将 字段库 序号复制到变量_XH,用来锁定 程序字段 和 数据来源字段
        IF LEFT(字段类型,1)="C"           &&如果是字符型则直接替换,否则转换为数值型后替换
            SELECT &_bstfile
            REPLACE (FIELD(_bstList)) WITH CHRTRAN(arrFields[_XH],'"','')
        ELSE
            SELECT &_bstfile
            REPLACE (FIELD(_bstList)) WITH VAL(CHRTRAN(arrFields[_XH],'"',''))
        ENDIF
    ENDFOR
ENDFOR

[此贴子已经被作者于2018-1-30 13:55编辑过]

2018-01-30 11:20
厨师王德榜
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:199
帖 子:995
专家分:4966
注 册:2013-2-16
收藏
得分:0 
最后,说一下本文发布之后的一点改进:
“字段对照表”中参数的名称,现在改为保存在FIELD_DEFA中,同时FIELD_NAME需保持为空,
 此改进是为了避免用户表中恰好有列的名字叫“参数1”,造成转换字段名称时产生混乱。

本算法目前尚未解决的问题,或者说是小小的缺憾:
 处理文本文件中要转换为日期型的列时,先把可能与系统当前日期分割符不同的先改为与系统一致,再进行字段类型转换,
 不过即使做了也同样有缺憾,比如文本中的日期是英式日期“01-30-2016”而系统当前日期格式为“2016-01-30”,那么
  即使日期分割符相同了,转换日期数据仍会出错。

 要避免这个问题,可能还需要一个专门的子过程,判断文本中的日期格式,但这样一来,复杂度上升了,所以只好暂时先不管。
各位如果有好的经验,可以分享一下?
2018-01-30 16:03
yewxj
Rank: 3Rank: 3
等 级:论坛游侠
威 望:5
帖 子:157
专家分:153
注 册:2015-6-18
收藏
得分:0 
*-*创建表并添加字段
_bstfile="数据_"+_yyyymmdd
CREATE dbf &_bstfile (序号 N(8))
SELECT 字段库
GOTO TOP
DO WHILE !EOF()
    IF LEN(ALLTRIM(程序字段)) > 0 AND 是否启用 = "是"
        _fN = 程序字段
        _fT = 字段类型
        *ALTER TABLE &_bstfile ADD &_fN &_fT
        ALTER TABLE &_bstfile ADD &_fN C(60)
     ENDIF
     SKIP   
ENDDO

*-*将字段库中不使用的字段序号存入数组arrXH
SELECT 字段库
COUNT TO i FOR LEN(ALLTRIM(程序字段)) = 0 AND 是否启用="否"
DIMENSION arrXH(i)
GOTO TOP
DO WHILE !EOF()
    IF LEN(ALLTRIM(程序字段)) = 0 AND 是否启用="否"
    AINS(arrXH,1)
    arrXH[1]=序号
    ENDIF
    SKIP
ENDDO

*-*向空表中添加数据
_cData = FILETOSTR(_bst)
_nLines = ALINES(arrData, _cData)        &&表的行数
FOR i=2 TO _nLines
    ALINES(arrFields, arrData[i], ",")
    FOR n=1 TO ALEN(arrXH)
      ADEL(arrFields,arrXH[n])           &&删除数据数组中不使用的内容
    ENDFOR
    AINS(arrFields,1)
    arrFields[1]=i-1                     &&第一列序号
    INSERT INTO &_bstfile FROM ARRAY arrFields
ENDFOR

这样效率提升很多,下一步需要把文本列改为需要的数值型、日期型


[此贴子已经被作者于2018-1-30 16:34编辑过]

2018-01-30 16:17
jsjd879087jd
Rank: 1
等 级:新手上路
帖 子:6
专家分:0
注 册:2018-2-20
收藏
得分:0 
学习了
2018-02-20 13:47
快速回复:求助如何将非dbf表(.csv文件)有选择的添加到dbf表里
数据加载中...
 
   



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

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