Управление файлами Excel с Windows Scripting Host - PullRequest
2 голосов
/ 20 апреля 2009

Существует ли быстрый способ манипулирования содержимым существующего файла XLS с Windows Scripting Host?

У нас есть шаблоны Excel, которые мы получили от клиента. Наша задача - заполнить эти шаблоны данными, которые мы получаем из базы данных Oracle.

Текущий подход заключается в использовании Windows Scripting Host и VBScript:

  1. Получение данных из Oracle с использованием ADODB:

    Set db = CreateObject("ADODB.Connection")
    SQL = "SELECT ..."
    Set rs=db.execute(SQL)
    
  2. Создание объекта Excel в Windows Scripting Host с использованием VBScript:

    Set objExcel = CreateObject("Excel.Application")  
    Set objWorkbook = objExcel.Workbooks.Open(xls_final)  
    Set objSheet = objWorkBook.Sheets(1)
    
  3. А затем заполните шаблон ячейка за ячейкой так:

    If rs.EOF = False Then
       rs.MoveFirst
       Do Until rs.EOF
          objSheet.Cells(RowNumber, 1).Value = rs("COLUMN1")
          objSheet.Cells(RowNumber, 2).Value = rs("COLUMN2")
          objSheet.Cells(RowNumber, 3).Value = rs("COLUMN3")
          rs.MoveNext
       Loop
    End If
    objWorkbook.Save 
    rs.Close
    

    Проблема в том, что некоторые из этих файлов содержат много данных, и для их заполнения требуются часы. Есть ли более быстрый способ сделать это?

Ответы [ 4 ]

5 голосов
/ 20 апреля 2009

Я думаю, у тебя все в порядке:

Set db = CreateObject("ADODB.Connection")
SQL = "SELECT ..."
Set rs=db.execute(SQL)

Set objExcel = CreateObject("Excel.Application")  
Set objWorkbook = objExcel.Workbooks.Open(xls_final)  
Set objSheet = objWorkBook.Sheets(1)

Но, как вы обнаружили, остаток будет ужасно медленным. Взаимодействие с рабочими листами связано с большими издержками, которые вы платите за каждый столбец в каждой строке. Есть несколько способов обойти это.

Самый простой

objSheet.Cells(1,1).CopyFromRecordset rs

, который я рекомендую вам попробовать первым.

2 голосов
/ 20 апреля 2009

взгляните на это.
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=49926
Это также может помочь, если вы подключаетесь к Excel, используя ADODB, а не манипулируете Excel. Если вам нужна помощь, прочитайте эту статью.
http://support.microsoft.com/kb/257819

1 голос
/ 20 апреля 2009

Одна из возможностей - сделать это двухэтапным процессом, но это зависит от того, где находится узкое место.

Если это Excel, просто превратите строки набора записей в файл типа CSV, а затем, когда это будет сделано, создайте объект Excel и импортируйте весь файл в фиксированное место.

Это, вероятно, будет быстрее, чем операция за ячейкой.

Если вы не можете импортировать CSV в фиксированное местоположение на листе (если ячейки не находятся в последовательных строках или столбцах), я импортирую CSV на новый лист, а затем делаю массовые копии оттуда в шаблон лист.

Диапазоны перемещения также должны быть быстрее, чем операции по ячейкам.

Это массовый импорт и массовое копирование, которые должны дать вам хорошее улучшение. У меня были листы, которые обрабатывали отдельные ячейки, которые ускорились по многим показателям в 10 раз, когда вы используете более сложную функциональность Excel (подумайте, используя = sum (a1..a999) вместо добавления каждой отдельной ячейки в VBA и размещения этого значения где-то ).

Что касается того, как выполнить импорт из VBA, я всегда полагаюсь на функцию "Record Macro", чтобы получить базовый уровень, который можно изменить (для тех, с кем я не очень близко знаком). Этот импортирует c:\x.csv в текущий лист в C7:

With ActiveSheet.QueryTables.Add(Connection:="TEXT;C:\x.csv", _
    Destination:= Range("C7"))
    .Name = "x"
    .FieldNames = True
    .RowNumbers = False
    .FillAdjacentFormulas = False
    .PreserveFormatting = True
    .RefreshOnFileOpen = False
    .RefreshStyle = xlInsertDeleteCells
    .SavePassword = False
    .SaveData = True
    .AdjustColumnWidth = True
    .RefreshPeriod = 0
    .TextFilePromptOnRefresh = False
    .TextFilePlatform = 850
    .TextFileStartRow = 1
    .TextFileParseType = xlDelimited
    .TextFileTextQualifier = xlTextQualifierDoubleQuote
    .TextFileConsecutiveDelimiter = False
    .TextFileTabDelimiter = True
    .TextFileSemicolonDelimiter = False
    .TextFileCommaDelimiter = True
    .TextFileSpaceDelimiter = False
    .TextFileColumnDataTypes = Array(1, 1, 1)
    .TextFileTrailingMinusNumbers = True
    .Refresh BackgroundQuery:=False
End With

Теперь я уверен, что большую часть этого мусора можно удалить, но было бы разумно сделать это по одному, чтобы не было проблем.

Вы также можете изменить это с помощью чего-то вроде следующего, чтобы использовать другой лист.

dim ws as worksheet
dim savealert as boolean
set ws = Sheets.Add
ws.select
' Put all that other code above in here. '
' Move all that data just loaded into a real sheet. '
savealert = Application.DisplayAlerts
Application.DisplayAlerts = False
ws.delete
Application.DisplayAlerts = savealert
0 голосов
/ 23 апреля 2009

Вы можете получить к нему доступ через соединение OLEDB, и это будет бесконечно быстрее.

Вот некоторый код из скрипта, который я использую для импорта данных из электронной таблицы в базу данных. Очевидно, вы захотите изменить тип курсора и тип блокировки, но вы поняли идею.

strExcelConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & objFile.Path & ";Extended Properties=""Excel 8.0;HDR=Yes"""
strSQL = "SELECT * FROM [RegistrationList$] ORDER BY DateToRegister DESC"

objExcel.Open strSQL, strExcelConn, adOpenForwardOnly, adLockReadOnly, adCmdText
...