Найти тему
Некто

Статья 11. Перенос данных из DBF в XLS или XLSX файлы на VBScript с использованием ADO. Работа с данными и рабочими листами.

В 10 статье я отметил, что процесс переноса данных из dbf в EXCEL файлы можно сделать почти также как из dbf в EXCEL. Но вот ведь в чем хорошо основано понятие, что при создании листа в EXCEL обязательно надо создать поле – заголовок. Это почти также как и создать dbf файл. Без полей Вы не создадите dbf файл. Так же не создадите EXCEL файл. Необходимо прописать хоть одно поле на создаваемом листе. И это во многом так, если у Вас на компьютере нет MS office (EXCEL). Если же он есть, то Вы можете легко обращаться напрямую c помощью CreateObject("Excel.Application"). Но бывало, Я удалял office и также мог обращаться напрямую. Но все равно это ничего не давало, потому что, для визуализации Visible=true необходима установка EXCEL приложения. Поэтому делать расчеты и другие действия Вы может только относительно полей самой книги на листе. Это Вы можете позволить себе. Здесь это так, а если есть у кого интересные подходы к этому, то ниже под статьей не поленитесь, и напишите про это.

В статье 10 Я указал, что при работе скрипта рабочий лист в EXCEL книги создается автоматически и не каждому пользователю есть желание это прояснять. Создается и создается. Данные переносятся и переносятся, а как называется лист (имя листа) и зачем это. Да, сейчас очень много людей, которые работают в EXCEL, и есть такие, которые дотошно его изучают и можно сказать фанатеют от него. Вот им хочется знать, как создать лист с именем, которое они могут сами придумать, да и наверно и знают они.

Вот такой фрагмент переноса данных из dbf в EXCEL

NameFil=SDefaultDir & "\_222.xls"

SQL="create table " & NameFil & ".[xls] ("

for i=0 to objKlFields-1

st=RS.Fields(i).Name

if i=objKlFields-1 then

SQL=SQL & "st" & i & " TEXT)"

else

SQL=SQL & "st" & i & " TEXT,"

end if

next

Создается EXCEL файл с листом xls

Если файл существует, то можно добавить еще лист, только с другим названием.

SQL="create table " & NameFil & ".[Sheet1] ("

А можно и так

cnnMain.Execute "CREATE TABLE Sheet1 (stt1 text)"

cnnMain.Execute "CREATE TABLE Sheet2 (stt2 text)"

cnnMain.Execute "CREATE TABLE Sheet3 (stt3 text)"

Создается лист Sheet1, Sheet2, Sheet3 и поле Stt1, Stt2, Stt3

А потом открыть эти листы и дописать

cnnMainR.open "SELECT * FROM [Sheet1$]",cnnMain,2,2

cnnMainR.Fields("Stt1").Value = "Привет1"

cnnMainR.Update

cnnMainR.Close

А можно и не делать SELECT а прям сразу перейти и добавить строку

cnnMainR.open "[Sheet3$]",cnnMain,1,3

cnnMainR.AddNew

cnnMainR.Fields("Stt3").Value = "Привет3"

cnnMainR.Update

cnnMainR.Close

Можете переходить между листами.

Но это когда Вы создаете новый рабочий лист. Можно создать новый рабочий лист и перенести в него данные того же dbf повторно. А вот добавить новые поля, вот здесь необходимо сделать так.

cnnMain.Execute("ALTER TABLE _222.xls.[xls$] ADD COLUMN str4 TEXT")

cnnMain.Execute("ALTER TABLE _222.xls.[xls$] ADD COLUMN str5 TEXT")

cnnMain.Execute("ALTER TABLE _222.xls.[xls$] ADD COLUMN str10 TEXT")

Причем это надо сделать до процесса переноса данных из dbf файла, а тогда когда копируются и создаются поля заголовки согласно, полей dbf файла. Если Вы переносите 3 колонки из dbf, то Вы можете добавить в create еще колонки, но здесь надо это грамотно это сделать. Например, если хотите добавить еще колонку st4, то это выглядит так.

SQL="create table " & NameFil & ".[xls] ("

for i=0 to objKlFields-1

if i=objKlFields-1 then

SQL=SQL & "st4" & " TEXT)"

Здесь надо убедить dbf файл, что у него 4 колонки. objKlFields= objKlFields+1

Доказать этому dbf файлу что перенос будет осуществляться из 3 колонок, а в четвертой колонке будут произведены и записаны расчеты

if j=objKlFields-1 then

st=2*i

stN=stN & "st4)"

vvv=vvv & st & "'"

else

st=RS.Fields(j)

stName="st"&j

stN=stN & stName & ","

vvv=vvv & st & "'" & "," & "'"

end if

Но лучше это сделать, как я указал с помощью ALTER. Все в Вашем понимании и нудном старании. Здесь хоть видно, что Вы добавляете, какие колонки (столбцы)

При записи также можете указать лист

SQL="insert into" & NameFil & ".[xls$]" & " " & stN & " values(" & vvv& ")"

Если делаете это не автоматически и если в книге 1 рабочий лист под указанное имя.

Можно позиционировать запись данных с помощью

cnnMainR.AbsolutePosition=10

cnnMainR.Fields(3).value="222"

cnnMainR.Update

cnnMainR.Requery

Можно определить количество строк в EXCEL файле

objKlRecs=RSQQ.RecordCount

и добавить результирующее решение

А можно добавить результирующее решение и так

objEndRecs=cnnMainR.RecordCount

cnnMainR.AbsolutePosition=objEndRecs-1 ' Предыдущая строка

cnnMainR.AbsolutePosition=objEndRecs

cnnMainR.AddNew ' Добавить новую строку

cnnMainR.Fields(3).value=SumSt4 'Можно и так

cnnMainR.Update

cnnMainR.Requery

где в общем SumSt4 посчитать.

А можно просто поставить

cnnMainR.AbsolutePosition=30 ' и перейти на конец записей и добавить результирующее решение. 30 взято условно. Если на рабочем листе 40 записей, то можно взять 41 и т.д. и т.п.

Все в Ваших руках и в Вашем понимании этих решений и Ваших познаний. Экспериментирование это стезя благородства в нужное время и концентрации этого понятия. Что быстрее это надо проверять на больших файлах.

И вот здесь если Вы добавляете колонки и сделайте расчеты, то все это можно перенести обратно в dbf файлы с новыми колонками.

Добавляем на каждый лист данные

cnnMain.close

Set cnnMainR = CreateObject("ADODB.Recordset")

cnnMain.Open "DRIVER={Microsoft Excel Driver (*.xls)};DBQ=" & NameFil & ";Deleted=0;ReadOnly=0;Exclusive=0;"

cnnMain.CursorLocation = 3

cnnMainR.open "SELECT * FROM [Sheet1$]",cnnMain,2,2

cnnMainR.AddNew

cnnMainR.Fields("Stt1").Value = "Привет1"

cnnMainR.Update

cnnMainR.Close

cnnMainR.open "SELECT * FROM [Sheet2$]",cnnMain,2,2

cnnMainR.Fields("Stt2").Value = "Привет2"

cnnMainR.Update

cnnMainR.Close

' cnnMainR.open "[Sheet3$]",cnnMain,2,2 " Можно и так

cnnMainR.open "[Sheet3$]",cnnMain,1,3

cnnMainR.AddNew

cnnMainR.Fields("Stt3").Value = "Привет3"

cnnMainR.Update

cnnMainR.Close

cnnMainR.open "SELECT * FROM [Sheet4$]",cnnMain,2,2

cnnMainR.AddNew

cnnMainR.Fields("Stt4").Value = "Привет4"

cnnMainR.Update

cnnMainR.Close

Начнем с 1 фрагмента. Здесь на листе xls с позиции 10 (строка) данные записанные в xSt4 переносим на рабочий лист Sheet3 в поле Stt3, а потом добавим эту переменную в другое поле Stt4 на рабочий лист Sheet4.

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 1 фрагмент

cnnMainR.open"[xls$]",cnnMain,2,2

cnnMainR.AbsolutePosition=10

xSt4=cnnMainR.Fields(3).value

cnnMain.close

cnnMain.Open "DRIVER={Microsoft Excel Driver (*.xls)};DBQ=" & NameFil & ";Deleted=0;ReadOnly=0;Exclusive=0;"

cnnMain.CursorLocation = 3

cnnMainR.open "[Sheet3$]",cnnMain,2,2

cnnMainR.Fields("Stt3").Value = xSt4

cnnMainR.Update

cnnMainR.AddNew

cnnMainR.Fields("Str4").Value = xSt4

cnnMainR.Update

cnnMainR.Close

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

'WScript.Echo("Фрагмент 1. Файл создан!")

'WScript.Quit ' Если хотите просмотреть предыдущие решения

А вот здесь интересное. С листа xls переносим данные на лист Sheet3 с помощью выбора Select и записываем на странице Sheet3

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 2 фрагмент

cnnMain.close

Set cnnMainR = CreateObject("ADODB.Recordset")

cnnMain.Open "DRIVER={Microsoft Excel Driver (*.xls)};DBQ=" & NameFil & ";Deleted=0;ReadOnly=0;Exclusive=0;"

cnnMain.CursorLocation = 3

'strSQLn="SELECT * FROM [xls$]" ' Если все

'strSQLn="SELECT str4 FROM [xls$]" ' Если 1 колонку

strSQLn="SELECT * FROM [xls$D1:D10]" ' Если 1 колонку

Set RS = cnnMain.Execute(strSQLn)

KlFieldsN = RS.Fields.count

KlRecsN=RS.RecordCount

cnnMainR.open "[Sheet3$]",cnnMain,2,2

for i=1 to KlRecsN

cnnMainR.AddNew

stDn=RS.Fields(0)

cnnMainR.Fields("Str4").Value = stDn

cnnMainR.Update

RS.MoveNext

next

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

Переносим данные 2 колонок с листа xls на лист Sheet3

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

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 3 фрагмент

cnnMain.close

Set cnnMainR = CreateObject("ADODB.Recordset")

cnnMain.Open "DRIVER={Microsoft Excel Driver (*.xls)};DBQ=" & NameFil & ";Deleted=0;ReadOnly=0;Exclusive=0;"

cnnMain.CursorLocation = 3

strSQLn="SELECT * FROM [xls$D1:E10]" ' Если 2 колонки

Set RS = cnnMain.Execute(strSQLn)

KlFieldsN = RS.Fields.count

KlRecsN=RS.RecordCount

cnnMainR.open "[Sheet3$]",cnnMain,2,2

cnnMainR.Requery

cnnMainR.AbsolutePosition=1

for i=1 to KlRecsN

cnnMainR.AddNew

stDn1=RS.Fields(0)

stDn2=RS.Fields(1)

cnnMainR.Fields("Stt3").Value = stDn1

cnnMainR.Fields("Str4").Value = stDn2

cnnMainR.Update

RS.MoveNext

next

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

Здесь переносим данные с листа xls на лист Sheet1

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& фрагмент 4

cnnMain.close

Set cnnMainR = CreateObject("ADODB.Recordset")

cnnMain.Open "DRIVER={Microsoft Excel Driver (*.xls)};DBQ=" & NameFil & ";Deleted=0;ReadOnly=0;Exclusive=0;"

cnnMain.CursorLocation = 3

strSQLn="SELECT * FROM [xls$D1:D10]" ' Если 2 колонки

Set RS = cnnMain.Execute(strSQLn)

KlFieldsN = RS.Fields.count

KlRecsN=RS.RecordCount

cnnMainR.open "[Sheet1$]",cnnMain,2,2

cnnMainR.Requery

cnnMainR.AbsolutePosition=1

cnnMainR.MoveFirst

for i=1 to KlRecsN

cnnMainR.AddNew

stDn1=RS.Fields(0)

cnnMainR.Fields("Stt1").Value = stDn1

cnnMainR.Update

RS.MoveNext

next

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

Другой способ переноса с листа xls в Sheet1

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& фрагмент 5

cnnMain.close

Set cnnMainR = CreateObject("ADODB.Recordset")

cnnMain.Open "DRIVER={Microsoft Excel Driver (*.xls)};DBQ=" & NameFil & ";Deleted=0;ReadOnly=0;Exclusive=0;"

cnnMain.CursorLocation = 3

strSQLn="SELECT * FROM [xls$D1:D10]" ' Если 2 колонки

Set RS = cnnMain.Execute(strSQLn)

KlFieldsN = RS.Fields.count

KlRecsN=RS.RecordCount

cnnMainR.open "[Sheet1$]",cnnMain,2,2

cnnMainR.Requery

cnnMainR.AbsolutePosition=1

for i=1 to KlRecsN

stDn1=RS.Fields(0)

SQL="insert into " & NameFil & ".[Sheet1$]" & " (stt1) values(" & "'" & stDn1 & "'" & ")"

cnnMain.Execute(SQL)

RS.MoveNext

next

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

Перенос данных с листа xls на 4 рабочий лист Sheet4

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& фрагмент 6

cnnMain.close

Set cnnMainR = CreateObject("ADODB.Recordset")

cnnMain.Open "DRIVER={Microsoft Excel Driver (*.xls)};DBQ=" & NameFil & ";Deleted=0;ReadOnly=0;Exclusive=0;"

cnnMain.CursorLocation = 3

strSQLn="SELECT * FROM [xls$D1:D10]" ' Если 2 колонки

Set RS = cnnMain.Execute(strSQLn)

KlFieldsN = RS.Fields.count

KlRecsN=RS.RecordCount

cnnMainR.open "[Sheet4$]",cnnMain,2,2

cnnMainR.Requery

cnnMainR.AbsolutePosition=1 ' Можно оставить, а можно убрать не влияет

cnnMainR.MoveFirst

for i=1 to KlRecsN

cnnMainR.AddNew

stDn1=RS.Fields(0)

cnnMainR.Fields("Stt4").Value = stDn1

cnnMainR.Update ' Иногда не нужно, Можно проверять

RS.MoveNext

next

'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

Можно описывать все фрагменты, но прилагаю архивный файл Файлы11.rar и там, все понятно.

Но расскажу еще об одном фрагменте. В 12 фрагменте мне пришлось разработать особый алгоритм решения сортировки на листе.

for i=1 to KlRecsN

stDn1=RSK.Fields(0)

WScript.Echo(stDn1)

KlRecsNew=i+1

cnnMainR.Fields(5).Value=stDn1

strSQlDelNlist="DROP TABLE [Sheet4$F" & KlRecsNew & ":F]"

'Можно и так

strSQlDelNlist="DROP TABLE [Sheet4$F" & KlRecsNew & ":F" & KlRecsNew & "]"

cnnMain.Execute(strSQlDelNlist)

cnnMainR.Fields(0).Value=stDn1

strSQlDelNlist="DROP TABLE [Sheet4$A" & KlRecsNew & ":A21]"

cnnMain.Execute(strSQlDelNlist)

cnnMainR.MoveNext

RSK.MoveNext

next

Все дело в том, что при перезаписи данных появляется вот такая проблема. Если появляется хоть бы 1 одинаковая запись по колонке, и она находится дальше чем 1 такая запись, то курсор перескакивает в последнюю запись и перезаписывает там данные, а если эти данные находятся в самом конце колонки или близко, то появляется ошибка. Причем другие данные не изменяются. Конечно, можно сделать фильтр отсортированных записей на другой рабочий лист и этим решить такую проблему именно в EXCEL, но как это сделать в dbf файле. Вот здесь приходится отсортировать данные и записать их заново на свои позиции. Конечно, можно создать 2 dbf файл и туда записать отсортированные данные, но это все-таки 2 файл. Можно придумать и другие решения, но в ADO это надо поискать. ADO хранит не мало секретов…

Заранее сохраните файлы _333.xls и _444.xls в любом другом каталоге для повторного применения. В файле AdoED11A.vbs Я также добавил понятие поиска, фильтра и update, а также работу с рабочими листами и сортировку. Удаление данных с листа в EXCEL предполагает просто очистку строк и ячеек. Удалить строки не предоставляется драйвером. Также не предоставляется удаление рабочего листа. Я не нашел такого решения.

Зато на рабочем листе можно записать данные согласно, выбранных ячеек. Все это мной проверено, и Я проделывал это и на других компьютерах. Все работало и получалось. AdoED11A.vbs загружает файл _111.dbf и на выходе получаем файл _222. xls. В файле AdoED11B.vbs реализована сортировка на одном рабочем листе. Здесь алгоритм создан мною и себя оправдывает. Также проверял. Работает этот файл с файлами _333.xls и _444.xls . Можно отсортировывать и большие файлы. Главное не прерывать процесс сортировки. Поэтому заранее сохраните эти файлы. Можно конечно повторно сортировать по выбранным полям. Заголовки полей должны быть на латинице. Могу добавить, что работа с EXCEL файлом полностью отожествляет собой работу с базами данных и похоже на работу как бы с dbf файлами. Но здесь есть свои понятия, которые удобны. Это и работа с ячейками по колонкам и строкам. Немного напоминает работу с EXCEL приложением из Office. Работа и по полям-заголовкам. Напоминает работу с dbf файлами. Удобно и так и так. Очень занимательно. Даже есть какое-то преимущество в этом. И книга может содержать большое количество рабочих листов. Можете представить их как dbf файлы и области работы. Отдельные файлы dbf (таблицы) также можно собирать как бы в один контейнер. В FOXPRO файл DBC может включать в себя имена файлов и элементов, связанных с ним. Есть, конечно, свои отличия, но понятия почти похожи. Файл mdb в ACCESS, который может включать братство форматов. В следующей статье Я еще возможно допишу про некоторую работу с EXCEL, но постараюсь описать перенос данных с EXCEL файлов в текстовые файлы.

Файлы сохранил в архив Файлы11.rar

Пробуйте.

Ссылка на файл https://disk.yandex.ru/d/ZzpXLpmZ_ATRwg

Подписывайтесь на мой канал и ставьте лайки.