Import XLS to MS SQL without Excel loaded on computer

Post Reply
User avatar
cdmmaui
Posts: 708
Joined: Fri Oct 28, 2005 9:53 am
Location: Houston ∙ Chicago ∙ Los Angeles ∙ Miami ∙ London ∙ Hong Kong
Contact:

Import XLS to MS SQL without Excel loaded on computer

Post by cdmmaui »

Hello,

Is it possible to read XLS contents and import to SQL table without Excel loaded on a computer? If so, could someone please provide an example?

Thank you!
*~*~*~*~*~*~*~*~*~*
Darrell Ortiz
CDM Software Solutions, Inc.
https://www.cdmsoft.com
User avatar
Otto
Posts: 7020
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Re: Import XLS to MS SQL without Excel loaded on computer

Post by Otto »

Hello,
XLSX (since Office 2007) is based on OpenXML—essentially a ZIP with XML files.

viewtopic.php?f=3&t=13495&p=69231&hilit=word+zip#p69231

I think it’s similar to DOCX.

For import, I see three pragmatic options:

PowerShell + SqlBulkCopy (for XLSX)
PHP + PhpSpreadsheet (portable, also supports older XLS)
CSV export (simplest for Harbour via ODBC/ADO)

Best regards,
Otto
vilian
Posts: 1068
Joined: Wed Nov 09, 2005 2:17 am
Location: Brazil
Contact:

Re: Import XLS to MS SQL without Excel loaded on computer

Post by vilian »

Yes,
You can do it using FW_OpenADOExcelBook / FW_OpenAdoExcelSheet:

Example:
oRs := FW_OpenAdoExcelSheet( "test.xls" )
XBROWSER oRs FASTEDIT
oRs:Close()
oRs:ActiveConnection:Close()

Notes: The book is opened in exclusive mode. It is necessary to close the connection
object soon after use.

Microsoft ACE.OLEDB.12.0 provider must have been
installed on the computer. This can be installed by installing Microsoft Access
Runtime (free).
MSOffice is not required.
Sds,
Vilian F. Arraes
[email protected]
Belém-Pa-Brazil
csincuir
Posts: 483
Joined: Sat Feb 03, 2007 6:36 am
Location: Guatemala
Contact:

Re: Import XLS to MS SQL without Excel loaded on computer

Post by csincuir »

Hi Darrel,
Look at this new class I created, it might be useful to you: viewtopic.php?t=45969

Best regards.

Carlos Sincuir
JoséQuintas
Posts: 104
Joined: Tue Feb 09, 2021 4:20 pm

Re: Import XLS to MS SQL without Excel loaded on computer

Post by JoséQuintas »

I write this a long time ago.
Initial convert to PRG source code.
This year change to json too.
Sometimes I need to open file using libreoffice and save on excel format.

Code: Select all | Expand

/*
XLSTOPRG - Converte Excel para fonte PRG
José Quintas

Driver Microsoft 2016
https://www.microsoft.com/en-us/download/details.aspx?id=54920

*/

REQUEST HB_CODEPAGE_PTISO

#include "inkey.ch"
#include "directry.ch"
#include "ze_adoclass.ch"

PROCEDURE Main

   LOCAL cn, rs, cName, cTxt := "", nCont, oFile, aFileList, cPath := ".\"
   LOCAL aTableList, aList, aItem

   aFileList := Directory( cPath + "*.xls*" )

   Set( _SET_CODEPAGE, "PTISO" )
   SET DATE BRITISH
   SetMode( 33, 100 )
   CLS
   Inkey(1)
   FOR EACH oFile IN aFileList
      Inkey()
      ? oFile[ F_NAME]
      Inkey(1)
      cn := ExcelConnection( cPath + oFile[ F_NAME ] )
      cn:Open()
      rs := cn:openSchema(20) // adSchemaTables
      aTableList := {}
      DO WHILE ! Rs:Eof()
         IF ! "Print_Are" $ rs:Fields( "Table_Name" ):Value .AND. ;
               ! "FilterDatabase" $ rs:Fields( "Table_Name" ):Value
            AAdd( aTableList, rs:Fields( "Table_Name" ):Value )
            ? oFile[ F_NAME ], rs:Fields( "Table_Name" ):Value
         ENDIF
         rs:MoveNext()
      ENDDO
      rs:Close()
      cTxt := ""
      FOR EACH cName IN aTableList
         aList := {}
         ? cName
         Inkey(1)
         rs := cn:Execute( "SELECT * FROM [" + cName + "]" )
         cTxt += [// ] + Substr( cName, 1, Len( cName ) - 1 ) + hb_Eol()
         cTxt += "// "
         FOR nCont = 0 TO rs:Fields:Count() - 1
            cTxt += rs:Fields( nCont ):Name + iif( nCont == rs:Fields:Count() - 1, "", ", " )
         NEXT
         cTxt += hb_Eol() + hb_Eol()
         cTxt += [FUNCTION jq_] + hb_FNameName( oFile[ F_NAME ] ) + Ltrim( Str( cName:__EnumIndex ) ) + [()] + hb_Eol()
         cTxt += hb_Eol()
         cTxt += [   LOCAL aList := {}] + hb_Eol() + hb_Eol()
         DO WHILE Inkey() != K_ESC .AND. ! Rs:Eof()
            AAdd( aList, {} )
            aItem := {}
            cTxt += [   AAdd( aList, { ]
            FOR nCont = 0 TO rs:Fields:Count() - 1
               cTxt += ToString( rs:Fields( nCont ):Value ) + iif( nCont == rs:Fields:Count() - 1, "", ", " )
               AAdd( aItem, rs:Fields( nCont ):Value )
               AAdd( aTail( aList ), rs:Fields( nCont ):Value )
            NEXT
            cTxt += [ } )] + hb_Eol()
            rs:MoveNext()
         ENDDO
         rs:Close() // não classe
         cTxt += hb_Eol() + [   RETURN aList]
         cTxt += hb_Eol() + hb_Eol()
         hb_MemoWrit( "Json" + Str( cName:__EnumIndex(), 1 ) + ".txt", hb_JsonEncode( aList ) )
      NEXT
      cn:Close() // não classe
      cn := NIL
      hb_MemoWrit( cPath + [jq_] + hb_FNameName( oFile[ F_NAME ] ) + [.prg], cTxt ) // + hb_Eol() + cTxtJson )
   NEXT

   RETURN

FUNCTION ExcelSheetName( cn )

   LOCAL cSheetName, Rs

   rs := cn:OpenSchema( AD_SCHEMA_TABLES )
   cSheetName := rs:Fields( "TABLE_NAME" ):Value
   rs:Close() // não classe

   RETURN cSheetName

FUNCTION ToSTring( xValue )

   DO CASE
   CASE xValue == NIL
      xValue := [""]
   CASE ValType( xValue ) == "D"
      xValue := ["] + Dtos( xValue ) + ["]
   CASE ValType( xValue ) == "N"
      xValue := Ltrim( Str( xValue ) )
      IF "." $ xValue
         DO WHILE Right( xValue, 1 ) == "0"
            xValue := Substr( xValue, 1, Len( xValue ) - 1 )
         ENDDO
         IF Right( xValue, 1 ) == "."
            xValue := Substr( xValue, 1, Len( xValue ) - 1 )
         ENDIF
      ENDIF
   OTHERWISE
      xValue := ["] + StrTran( xValue, ["], [] ) + ["]
      xValue := StrTran( xValue, Chr(13), " " )
      xValue := StrTran( xValue, Chr(10), " " )
   ENDCASE

   RETURN xValue

FUNCTION ExcelConnection( cFileName )

   LOCAL oConexao

   oConexao := win_OleCreateObject( "ADODB.Connection" )
   oConexao:ConnectionString := ;
      [Provider=Microsoft.ACE.OLEDB.12.0;Data Source=] + cFileName + ;
      [;Extended Properties="Excel ] + iif( ".xlsx" $ Lower( cFileName ), ;
      [12.0 Xml], [8.0] ) + [;HDR=YES";]
   // ;
   //   [Provider=Microsoft.Jet.OLEDB.4.0;Data Source=] + cFileName + ;
   //   [;Extended Properties="] + iif( ".xlsx" $ Lower( cFileName ), [Excel.12.0 Xml], [Excel 8.0] ) + [";] // HDR=Yes;IMEX=1";] // alterado em 16/10 pra teste

   RETURN oConexao

   /*
   a) OLEDB Provider Access/Excel “Microsoft.ACE.OLEDB.12.0”

   Excel add the appropriate Extended Properties of the OLEDB

   File Type (extension)                    Extended Properties
   ---------------------------------------------------------------------------------------------
   Excel 97-2003 Workbook (.xls)            "Excel 8.0"
   Excel Workbook (.xlsx)                   "Excel 12.0 Xml"
   Excel Macro-enabled workbook (.xlsm)     "Excel 12.0 Macro"
   Excel Non-XML binary workbook (.xlsb)    "Excel 12.0"

   b) ODBC Provider
   Access data, “Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=path to mdb/accdb file”
   Excel data,  “Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=path to xls/xlsx/xlsm/xlsb file”
*/

Code: Select all | Expand

FUNCTION ExcelConnection( cFileName, cVersion )

   LOCAL oConexao

   DO CASE
   CASE ValType( cVersion ) == "C"
   CASE ".xlsx" $ Lower( cFileName ); cVersion := "12.0 Xml" // XLSX
   //CASE "t00" $ Lower( cFileName )  ; cVersion := "5.0"  // 95 seems no more available
   OTHERWISE                        ; cVersion := "8.0" // 97/2000/XP
   ENDCASE
   oConexao := win_OleCreateObject( "ADODB.Connection" )
   oConexao:ConnectionString := ;
      [Provider=Microsoft.ACE.OLEDB.12.0;Data Source=] + cFileName + ;
      [;Extended Properties="Excel ] + cVersion + [;HDR=YES";]
      /* Allow Formula=true; consider start = as formula or not */

   RETURN oConexao

José M. C. Quintas Brazil
gtwvg, fivewin 25.12, hwgui, mingw 15.2 (32 bits)

User avatar
Massimo Linossi
Posts: 512
Joined: Mon Oct 17, 2005 10:38 am
Location: Italy

Re: Import XLS to MS SQL without Excel loaded on computer

Post by Massimo Linossi »

Hi
Very nice, compliments. I'm working on Linux with ModHarbour and there is no ADODB or Ole. Have you a solution for working on this OS ?
Thanks a lot
Massimo
User avatar
Otto
Posts: 7020
Joined: Fri Oct 07, 2005 7:07 pm
Contact:

Re: Import XLS to MS SQL without Excel loaded on computer

Post by Otto »

Introduction: XLSX Reader without Classes – functional, simple, transparent

Over the past few days I’ve collected some answers and code examples on the topic of Excel import without having Excel installed and summarized them in a PDF.
My main thought:

Does this really need to be a class?
From my perspective, not necessarily. In teams I often see that hardly anyone touches or overrides a class. In the end, usually only the original author fully understands what’s happening inside.

A functional approach is often simpler:

More transparent: each function does exactly one thing (e.g., unzip XLSX, load sharedStrings, iterate sheet).

Easier to maintain: no hidden state, no inheritance.

Team-friendly: contributors can immediately plug in their own logic, for example via callbacks.

Expandable: if more is needed (merged cells, large files, styles), you can extend specific functions — without having to understand a complex class structure.

In practice these building blocks cover 90% of common use cases:

Load and unzip XLSX

Iterate through cells

Validate or transform values

Output as CSV or insert directly into SQL

All based on simple functions + hashes/arrays.

In my view, this is a better default than a class: clearer, easier to maintain, and less fragile for collaboration.
Best regard,
Otto

https://clipper2web.com/php/importxlsto ... mputer.pdf
csincuir
Posts: 483
Joined: Sat Feb 03, 2007 6:36 am
Location: Guatemala
Contact:

Re: Import XLS to MS SQL without Excel loaded on computer

Post by csincuir »

Hi Otto.
I particularly like working with Classes; I find it easier to maintain, but your point is also valid.

Best regards.
Post Reply