Subject Re: import a csv file from excel
From Mervyn Bick <invalid@invalid.invalid>
Date Fri, 4 Aug 2023 10:45:28 +0200
Newsgroups dbase.getting-started
Attachment(s) APPEND_CSV.prg

On 2023/08/02 18:07, ED FURCHE wrote:
> how long should it take to import an excel.csv file of 2400 recs to a dbf?
> dbf is about 100 characters

Seconds rather than minutes.  I have a 5 field table (1 x autoinc, 2 x
char and 2 x date) that imports 9500 records from a .csv file in just
under 9 seconds.  The time taken does, however, depend on the computer,
the number of records and the number of fields.

How long is it taking and what code are you using?

The built-in way of appending from a .csv file

     USE WHATEVER
     APPEND FROM WHATEVER.CSV DELIMITED
     USE

has major drawbacks.  It will not import into memo fields and it only
saves dates to a date type field if they are in the format
..,yyyymmdd,... i.e no delimiters and no separators irrespective of the
date format on the computer.

As very few (if any) programs other than dBASE save dates in .csv files
in this format it means that, unless you are going to save dates to
character fields, you need a little program to import from a .csv file.
Fortunately the function breakstring() in stringex.cc in the dUFLP makes
this easy.

The biggest problem when adding data from a .csv to a .dbf file is
dealing with dates.  For what it's worth (it was written for my own use
and was never really intended to be distributed), the little program I
use is attached.  The program can deal with virtually any date or
datetime format in the .csv file.

If your date format in the .csv file is mm/dd/yyyy you only need to pass
the name of the .csv and .dbf files as parameters.  See the comments
under if nArg = 2  for a list of the various values that can be passed
as parameters.

   append_csv('whatever.csv','whatever.dbf')


With hindsight I should perhaps have placed the parameter for setting
the date format third as the date is the most likely to be different in
varous .csv files.  I have, however, used the program in too many
"wrapper" programs to make changes now.

If you need to set a specific parameter you will need to provide values
for ALL parameters up to, and including, that parameter.

Mervyn.





parameters cCSV,cTable,cSeparator,bSkipFirstRecord,cDateFormat,cDateSeparator,bIsWindows,bIsAutoInc
nArg = argCount()
if nArg < 2
   msgbox('At least an input file and an output table must be supplied')
   return
endif
if nArg = 2
  cSeparator= ','
  bSkipFirstRecord = false
   cDateFormat = 'a'
   // 'a'  mm/dd/yyyy; 'b' dd/mm/yyyyy; 'y'  yyyy/mm/dd; 'd' yyyymmdd
   cDateSeparator = '/'
   // '/' for British or American, '-' for Italian, '.' for German
   bIsWindows = true
   //False for .csv created in Unix.  As it stands the program can only deal with standard
   //Windows and Unix end-of-line markers.
   bIsAutoinc = false
   //True if first field in table is AutoInc.  
elseif nArg = 3
   bSkipFirstRecord = false
   cDateFormat = 'a'
   cDateSeparator = '/'
   bIsWindows = true
   bIsAutoInc = false
elseif nArg = 4
   cDateFormat = 'a'
   cDateSeparator = '/'
   bIsWindows = true
   bIsAutoInc = false
elseif nArg = 5
   cDateSeparator = '/'
   bIsWindows = true
   bIsAutoInc = false
elseif nArg = 6
   bIsWindows = true
   bIsAutoInc = false
elseif nArg = 7
  bIsAutoInc = false
endif  
set procedure to :duflp:stringex.cc
q = new query()
q.sql = 'select * from '+cTable
q.active = true
f = new file()
f.open(cCSV)
if bSkipFirstRecord
   cRead = f.gets(1000,iif(bIsWindows,chr(13)+chr(10),chr(10))) //Skip first record with field names
endif  
do while not f.eof()
   cRead = f.gets(1000,iif(bIsWindows,chr(13)+chr(10),chr(10)))
   if not empty(cRead)
      aArray = new stringex(cRead).breakstring(cSeparator, true)
      q.rowset.beginAppend()
      for n = iif(bIsAutoInc,2,1) to q.rowset.fields.size //Skip first field if it is autoinc
         if q.rowset.fields[n].type = 'DATE' or q.rowset.fields[n].type = 'DATETIME'
            q.rowset.fields[n].value = create_date(aArray[n],cDateFormat)
         else  
            q.rowset.fields[n].value = aArray[n]
         endif  
      next
      q.rowset.save()
   endif
enddo
f.close()
q.active = false

function create_date(cDate,cDateFormat)
    local nHr,nMin,nSec
    nHr = 0
    nMin = 0
    nSec = 0
   if cDateFormat <> 'd'
      c1 = substr(cDate,1,at(cDateSeparator,cDate)-1)
      c2= substr(cDate,at(cDateSeparator,cdate,1)+1,at(cDateSeparator,cDate,2)-at(cDateSeparator,cDate,1)-1)
      c3= substr(cDate,at(cDateSeparator,cdate,2)+1)
   else   // cDateFormat = 'd'
       if len(cDate) = 6 or at(' ',cDate) =7
         c1 = substr(cDate,1,2)
         c2= substr(cDate,3,2)
         c3= substr(cDate,5,2)
      else
         c1 = substr(cDate,1,4)
         c2= substr(cDate,5,2)
         c3= substr(cDate,7,2)
      endif
   endif
   if cDateFormat = 'y' or cDateFormat = 'd'
   //If the date format in the CSV file is yyyy/mm/dd or yyyymmdd
      yy = c1
      mm = c2
      dd = c3
   elseif cDateFormat = 'b'  
   //If the date format in the CSV is dd/mm/yyyy (British) use the following
      yy = c3
      mm = c2
      dd = c1
   elseif cDateFormat = 'a'  
  //If the date format in the CSV is mm/dd/yyyy (American) use the following
      yy = c3
      mm = c1
      dd = c2
   endif
   if len(cDate)>10  //timestamp
      cTime = rtrim(ltrim(substr(cDate,at(' ',cDate))))
      if ':'$cTime
         nHr = val(substr(cTime,1,at(':',cTime)))
      endif  
      if 'PM'$upper(cDate) and nHr <>12
         nHr += 12
      endif
      if 'AM'$upper(cDate) and nHr = 12
         nHr -= 12
      endif
      if at(':',cTime,1) < len(cTime)
         nMin = val(substr(cTime,at(':',cTime,1)+1))
      endif
      if at(':',cTime,2) > 0
         nSec = val(substr(cTime,at(':',cTime,2)+1))
      endif      
   endif
   if len(yy) = 2
      if substr(str(set('epoch'),4,0),3)>=yy
         yy = '20'+yy
      else
         yy = '19'+yy
      endif        
   endif
    dDate = new date(val(yy),val(mm)-1,val(dd),nHr,nMin,nSec)
   return dDate