Тема: VBS: Экспорт данных из книги Excel в таблицу б/д Access
Стоит задача создать скрипт для экспорта данных из файла excel в таблицу б/д Access
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Серый форум → Общение → Windows Script Host, HTA (VBScript, JScript) → VBS: Экспорт данных из книги Excel в таблицу б/д Access
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Стоит задача создать скрипт для экспорта данных из файла excel в таблицу б/д Access
Доброго вечера. ) Прошу прощения, но ваши дублированные вопросы я удалил. Дабы не было засорения форума. Сейчас воскресенье, знатоки отдыхают. ) Чуть позже попробую наваять пример. И прошу Вас, если Вам не ответили, не нужно испытывать форум на прочность и "UP-ать" тему. Как только кто то сможет Вам помочь - он тут же постарается это сделать.
Добавлено в 23:03
Хм.... уважаемый NecroTYN, а поиском вы пробовали пользоваться ? ![]()
Первый же запрос в GOOGLE с текстом "Excel в Access" даёт большинство необходимой информации. 5 секунд на набор строки и Вы получаете возможность поиска в бездонных недрах интернета.
Хм.... уважаемый NecroTYN, а поиском вы пробовали пользоваться ?
Конечно пробовал...
Дело вот в чем: экспорт встроенными средствами не подходит т.к. б/д используется другой программой, которая в свою очередь имеет поддержку VBS.
Схема работы должна выгядеть так: имеем таблицу со своими полями, одно из которых имеет статус вложения типа файл, вот это и есть тот самый файл Excel с которого нужно экспортировать данные
Я разве говорил что то про встроенные средства ? Логично, что если Вы задаёт вопрос на форуме посвящённом написанию скриптов, то Вам нужен скрипт.
Не зря спросил Вас о поиске.
Первая ссылка из результатов поиска ведёт нас к вот такому скрипту
ссылка
'функция упрощёного управляемого импорта из Excel
Sub excel_get()
Dim data(10, 10) As String 'буфер для хранения даных
Dim xlObj, xlWB As Object 'объект приложение и объект книга
'Запускаем Excel
Set xlObj = CreateObject("Excel.Application")
xlObj.Visible = False ' Тут же его скрываем
' Открываем определёную книгу
Set xlWB = xlObj.Workbooks.Open("D:\BASE_1.xls")
' Чиаем в книге первую страницу
i = 1
While xlWB.Sheets(1).Cells(i, 1) <> ""
j = 1
While xlWB.Sheets(1).Cells(i, j) <> ""
data(i, j) = xlWB.Sheets(1).Cells(i, j)
MsgBox xlWB.Sheets(1).Cells(i, j)
j = j + 1
Wend
i = i + 1
Wend
' стандарный выход
Set xlWB = Nothing
Set xlObj = Nothing
End SubВы вполне могли бы уточнить запрос поиска указав уточнение в виде "VBS". Т.е - "Excel в Access vbs". Разве это не логично ?
Такой запрос ведёт нас к уже с более наглядному примеру ссылка
Вы вполне могли бы уточнить запрос
Прошу прощения, но я уточнял ...
Открываем определёную книгу
Set xlWB = xlObj.Workbooks.Open("D:\BASE_1.xls")вот вопрос по коду:
как сделать чтобы путь к файлу Excel брался из поля таблицы, скажем tbl1.file
Такой запрос ведёт нас к уже с более наглядному примеру примером
Sub DAOFromExcelToAccess()
' exports data from the active worksheet to a table in an Access database
' this procedure must be edited before use
Dim db As Database, rs As Recordset, r As Long
Set db = OpenDatabase("C:\FolderName\DataBaseName.mdb")
' open the database
Set rs = db.OpenRecordset("TableName", dbOpenTable)
' get all records in a table
r = 3 ' the start row in the worksheet
Do While Len(Range("A" & r).Formula) > 0
' repeat until first empty cell in column A
With rs
.AddNew ' create a new record
' add values to each field in the record
.Fields("FieldName1") = Range("A" & r).Value
.Fields("FieldName2") = Range("B" & r).Value
.Fields("FieldNameN") = Range("C" & r).Value
' add more fields if necessary...
.Update ' stores the new record
End With
r = r + 1 ' next row
Loop
rs.Close
Set rs = Nothing
db.Close
Set db = Nothing
End Subимеем таблицу со своими полями, одно из которых имеет статус вложения типа файл, вот это и есть тот самый файл Excel с которого нужно экспортировать данные
Вы, во-первых, употребляете терминологию, которую понимаете только вы сами, и во-вторых, описываете задачу столь кратко, как будто мы телепаты.
Прошу прощения, но я уточнял ...
Я говорил об уточнении запроса для поисковой системы GOOGLE.
вот вопрос по коду:
как сделать чтобы путь к файлу Excel брался из поля таблицы, скажем tbl1.file
В примере, который Вы уже посмотрели, есть ответ на Ваш вопрос.
Set xlWB = xlObj.Workbooks.Open("D:\BASE_1.xls")
......
xlWB.Sheets(1).Cells(i,j)
Вы, во-первых, употребляете терминологию, которую понимаете только вы сами, и во-вторых, описываете задачу столь кратко, как будто мы телепаты.
Работа с базой данных происходит через программу Склад и торговля
Имеем базу данных Access со своими таблицами. Есть таблица "Заказы" и подчиненная ей "Смета заказа", имеется также и программа которая выдает нам *xls файл сметы...
В таблице "Смета заказа" имеется поле "Файл сметы" которое имеет статус ссылка на файл, вот именно в этом поле и записывается путь к файлу сметы...
Задача стоит вот такая:
При указании пути к файлу сметы, наш скрипт должен считать путь к файлу из поля и записать данные из файла Excel в таблицу "Смета заказа"
Все упомянутые мною файлы можно скачать по данной ссылке, в архиве есть также скриншот имен полей таблицы...
При указании пути к файлу сметы, наш скрипт должен считать путь к файлу из поля...
Не понял. Нам известен путь к XLS файлу сметы или мы его всё-таки должны найти в таблице Access? При указании пути к файлу считать путь к файлу...
Я так понял, что из Access таблицы 1 мы считываем путь к XLS файлу и всё что считываем из XLS пишем в таблицу 2. Правильно?
Посмтрел скрины, MDB, XLS, сразу напрашивается вопрос: а Торговля и Склад точно не умеет делать то, что вы собираетесь делать скриптом?
Не понял. Нам известен путь к XLS файлу сметы или мы его всё-таки должны найти в таблице Access? При указании пути к файлу считать путь к файлу...
Пошагово:
1. Получаем файл сметы *.xls и сохраняем его в нужной нам директории
2. В программе Склад и торговля открываем таблицу заказы и заходим в ее подчиненную "Смета заказа", где в поле "Файл Сметы"(EstimatesFail) указываем путь к файлу Смета.xls
Я так понял, что из Access таблицы 1 мы считываем путь к XLS файлу и всё что считываем из XLS пишем в таблицу 2. Правильно?
Если вы говорите про вторую таблицу в файле Б/Д Database111.mdb то нет, это таблица для параметров раскроя материала, о кторой речь подет позже
Посмтрел скрины, MDB, XLS, сразу напрашивается вопрос: а Торговля и Склад точно не умеет делать то, что вы собираетесь делать скриптом?
Нет, к сожалению не умеет
Пошагово:
1. Получаем файл сметы *.xls и сохраняем его в нужной нам директории
2. В программе Склад и торговля открываем таблицу заказы и заходим в ее подчиненную "Смета заказа", где в поле "Файл Сметы"(EstimatesFail) указываем путь к файлу Смета.xls
Я правильно понимаю, дальше нажимается настраиваемая кнопка(форум Склад и торговля=>Скрипты VBS для экспорта и чтения), и скрипт закидывает данные в базу?
Или скрипт запускается извне?
Если честно, то не очень понятна структура БД. Судя по форуму разработчика, как минимум записи подчинённой таблицы связаны с родительской по ID операции. Соответственно для запуска скрипта нужен или этот ID(по нему можно получить путь к файлу), или путь к файлу.
Не удержался, скачал и попробовал и 1-ую, и 2-ую ветку указанной программы - таких таблиц в демо-базе не нашел. Хотя не думаю что это существенно, возможно Вы добавили таблиц под свой функционал.
Что до технической стороны, то всё просто. В закладке нужной таблицы создаём новую кнопку(команда - "запуск программы") на запуск скрипта. Пример параметров:
X:\knopka1.vbs /[qdfClaims].[ID]
X:\knopka1.vbs /[qdfClaimsProducts].[ID]
В качестве параметра скрипту передаётся ID выделенной строки главной(первый вариант) или подчинённой таблицы. На самом деле это не таблицы, а запросы к ним - почему именно так я не разбирался, делал как подсказывала сама программа.
Правда параметр в скрипт передаётся со слэшом(легко убрать прямо в скрипте). Без слэша запуск скрипта не срабатывает(ПО версии 1.98, 2.140 - пишет что файл не найден), полагаю особенность реализации запуска скрипта создателями программы ![]()
Дальше всё банально - подключиться через ADO к MDB и XLS, считать данные в экселе и закинуть в MDB.
dsb пишет:Посмтрел скрины, MDB, XLS, сразу напрашивается вопрос: а Торговля и Склад точно не умеет делать то, что вы собираетесь делать скриптом?
Нет, к сожалению не умеет
А это не оно?
Файл помощи => Руководство Администратора => Импорт
В начале работы с программой Вам, скорее всего, понадобится импортировать данные из других источников. В программе можно импортировать данные из CSV-файлов или из Microsoft Excel. Для этого войдите в Меню > Файл > Импорт.
Если в закладку главной таблицы добавить свою кнопку "Import", то по нажатию на неё главная таблица даже будет сразу выбрана как приёмник данных(на подчинённую можно легко переключиться).
P.S. примеры работы с программой из VBS есть в папке с программой(ScriptExample3.vbs - получение параметров; ScriptExample1.vbs и ScriptExample2.vbs - работа с базой).
P.P.S. не понимаю зачем хранить путь к файлу сметы в таблице смет, а не в таблице заказов. Мне кажется, логичнее было бы завети под файл смет колонку в таблице заказов, а в таблицу смет добавлять непосредственно данные из файла со связью с главной таблицей по ID заказа. В скрипт передавать ID заказа и путь к файлу. Если параметр в виде строки с пробелами, нужно экранировать: C:\Program Files\Копия ProductsCount\knopka1.vbs /[qdfClaimsProducts].[ID] /""test with space""; если строка с пробелами берётся из БД(например [qdfClaimsProducts].[ProductCalc] = "Процессор Intel") экранировать не требуется(C:\Program Files\Копия ProductsCount\knopka1.vbs /[qdfClaimsProducts].[ID] /[qdfClaimsProducts].[ProductCalc]).
Я правильно понимаю, дальше нажимается настраиваемая кнопка(форум Склад и торговля=>Скрипты VBS для экспорта и чтения), и скрипт закидывает данные в базу?
Или скрипт запускается извне?
Нет, скрипт должен запускаться автоматически - по условию на поле "Файл сметы" - команда запуска прописывается в тригерах таблицы
Соответственно для запуска скрипта нужен или этот ID
В триггерах при запуске файла надо указать так: C:\Program Files (x86)\ProductCount\smeta.vbs /[ID] (где smeta.vbs является нашим скриптом )и все работает нормано
возможно Вы добавили таблиц под свой функционал.
так и есть
...не понимаю зачем хранить путь к файлу сметы в таблице смет, а не в таблице заказов. Мне кажется, логичнее было бы завети под файл смет колонку в таблице заказов, а в таблицу смет добавлять непосредственно данные из файла со связью с главной таблицей по ID заказа.
Да, здесь вы наверное правы, так наверное будет правильней
Нет, скрипт должен запускаться автоматически - по условию на поле "Файл сметы" - команда запуска прописывается в тригерах таблицы
Нашел на SQL.RU костыль для реализации "триггеров" в MDB. Поражен ![]()
Правда под вечер не могу понять как-же этот функционал реализован...
В триггерах при запуске файла надо указать так: C:\Program Files (x86)\ProductCount\smeta.vbs /[ID] (где smeta.vbs является нашим скриптом )и все работает нормано
Т.е. в данный момент всё работает?
Нашел на SQL.RU костыль для реализации "триггеров" в MDB. Поражен
Правда под вечер не могу понять как-же этот функционал реализован...
Выдержка из мануала
Вместо SQL-инструкции в качестве триггера можно указать файл для запуска (например, файл .VBS с программным кодом на языке VBScript, содержащий какой-то алгоритм модификации данных в БД). Для просмотра и создания триггеров предусмотрена кнопка "Триггеры" на панели инструментов, которая по умолчанию скрыта. Ее можно сделать видимой из контекстного меню по правому клику на панели инструментов.
Т.е. в данный момент всё работает?
Да нет, скрипта нет, вот и не работает...
NecroTYN, я что то устал заниматься герменевтикой ваших текстов. Раз вы не можете внятно объяснить задачу и свои затруднения, то и любые дельные советы без утомительного их жевания вам на пользу не пойдут.
NecroTYN, я что то устал заниматься герменевтикой ваших текстов.
Вот то что нужно получить
Пошагово:
1. Получаем файл сметы *.xls и сохраняем его в нужной нам директории
2. В программе Склад и торговля открываем таблицу "Заказы"(tblOrders), где в поле "Файл Сметы"(EstimatesFail) указываем путь к файлу Смета.xls
скрипт должен считать путь к файлу из таблицы "Заказы" и экспортировать данные из файла *.xls в таблицу "Смета заказа"(tblEstimatedOrder), по условию <>Null на поле "Файл сметы"(команда запуска прописывается в тригерах таблицы)
Выдержка из мануала
Прекрасно - костыль вставлен в саму программу ![]()
MSDE/SQLExpress всё равно был бы гораздо удобнее, функциональнее и гибче(ИМХО).
Для наличия возможности проверки сделал вчерне скрипт для стандартных таблиц заказа. Как образец "взять оттуда - положить туда" сойдёт.
Срабатывание "триггера": вставки или изменение
Условие "триггера": [Notes]<>''
"триггер": x:\trigger1.vbs /<ID>
trigger1.vbs:
' VB Script Document
option explicit
' константы для работы с ADO
Const adDouble = 5, adDate = 7, adCurrency = 6, adBoolean = 11, adVarWChar = 202, adLongVarWChar = 203
Const adUseClient = 3, adOpenStatic = 3, adLockOptimistic = 3, adCmdText = &H1
Const adSchemaTables = 20, adSchemaColumns = 4
'1. получаем ID заказа:
Dim oArgs 'объекта для чтения параметров строки запуска файла
Set oArgs = WScript.Arguments 'получение объекта для чтения параметров строки запуска файла
Dim OrderID
OrderID = Trim(Replace(oArgs(0),"/","")) 'trim на всякий пожарный
'2. получаем путь к файлу
Dim oConMDB
Set oConMDB = CreateObject("ADODB.Connection")
'http://www.connectionstrings.com/access
With oConMDB
.Provider = "Microsoft.Jet.OLEDB.4.0"
.Open "C:\Documents and Settings\vb.user\Мои документы\Склад и торговля\DemoDatabase.mdb"
End With
Dim oRs, File
Set oRs = oConMDB.Execute("Select [Notes] from [tblOrders] Where ID = " & OrderID)
File = oRs("Notes").Value
'3. открываем таблицу
Dim oConXLS
Set oConXLS = CreateObject("ADODB.Connection")
'http://www.connectionstrings.com/excel
With oConXLS
.Provider = "Microsoft.Jet.OLEDB.4.0"
.Properties("Extended Properties").Value = "Excel 8.0;IMEX=1;Hdr=Yes;Mode=Read;"
.CursorLocation = adUseClient
.Open File
End With
Dim oRsX
Set oRsX = oConXLS.Execute("Select * from [Общая$]")
Dim sOrdinal, sProductCode, sQuantity, sSalePrice, sAmount, sNotes, sAddTime, sOrderID
sOrderID = OrderID
sOrdinal = 0
sProductCode = 1
sAddTime = now
'4. проходим по записям таблицы и забрасываем данные в MDB:
Do While Not (oRsX.EOF)
sOrdinal = sOrdinal + 1
sProductCode = sProductCode + 1
sQuantity = oRsX("Расч#кол").Value
sSalePrice = oRsX("Цена").Value
sAmount = oRsX("Стоимость").Value
sNotes = ""
Set oRs = oConMDB.Execute("INSERT INTO [tblOrdersProducts] " & _
"(Ordinal, ProductCode, Quantity, SalePrice, Amount, Notes, AddTime, OrderID) " & _
"VALUES (CInt('" & sOrdinal & "'), CInt('" & sProductCode & "'), CDbl('" & sQuantity & "'), CCur('" & sSalePrice & "'), " & _
"CCur('" & sAmount & "'), CStr('" & sNotes & "'), CDate('" & sAddTime & "'), CInt('" & sOrderID & "'))")
oRsX.MoveNext
LoopПояснения:
п.1 - проверку наличия и числа аргументов не делал.
п.2 - корректность пути, существование файла не проверял.
п.3 - читал с заголовками таблицы(Hdr=Yes); несмотря на Mode=Read обнаружилась неоднозначная реакция на попутку открыть xls если он уже открыт. А именно: xls открыт на хост-системе; скрипт на хост-системе при этом работает нормально(запускал напрямую). Запуск скрипта в гостевой системе при уже открытом на хосте XLS вызывает ошибку из-за блокировки. Проверить на гостевой не могу - офис там не установлен. Ставить стрёмное ПО на рабочую систему желания нет, так что отладку проблем с блокировкой файла оставляю Вам
. Перебор листов в поисках нужного тоже не делал, сослался на то что было в файле образце
.
п.4 - на хосте всё было ОК и без преобразования, в виртуалке уже не прокатывало - пришлось приводить к типу близкому заданному в MDB. Отсутствующие в экселе данные заменил счётчиками(ибо см. Далее.2).
Далее.
1. Вариант запуска скрипта "триггером" не оптимален, т.к. скрипт будет запускаться при любом изменении записи(при непустом Notes). Это будет приводить к повторному добавлению данных по смете. Даже если можно прицепить его непосредственно на поле Notes(не пробовал, и желанием не горю), нет гарантии что не произойдёт случайного захода в поле для файла и его редактирования(промахнулись, вернули как было - событие свершилось -> дубли). Вешать на добавление - не сработает в случае если путь к файлу будет добавлен потом(по логике это уже не onInsert, а onUpdate). можно конечно предварительно проверять каждую добавляемую запись на предмет наличия в базе... Итого - кнопка всё-таки тут будет надёжнее. Возможно с добавлением в скрипт интерактивного запроса типа "А Вы уверены что хотите это сделать?".
2. В случае таблицы штатной заказов в ней наименование товара отсутствует - только ID товара из таблицы товаров. В экселе отсутствует ID, но есть наименование. Т.о. дополнительно необходимо получить для каждого наименования ID из таблицы товаров, и что-то сделать с товарами которых там нет(добавить? ещё запрос[ы]).
BeS Yara
Спасибо огромное !!!
Попробовал применить ваш код к своим таблицам, к сожалению с не получилось пишет ошибку...
---------------------------
Ошибка при вычислении условия триггера
---------------------------
Ошибка -2147217904 в Условие триггера: Отсутствует значение для одного или нескольких требуемых параметров.Команда: SELECT TOP 1 1 FROM [qdfOrders] WHERE [FileEstimated] IS NOT NULL AND ID = 1
Условие: [FileEstimated] <> Null
---------------------------
ОК
---------------------------
' VB Script Document
option explicit
' константы для работы с ADO
Const adDouble = 5, adDate = 7, adCurrency = 6, adBoolean = 11, adVarWChar = 202, adLongVarWChar = 203
Const adUseClient = 3, adOpenStatic = 3, adLockOptimistic = 3, adCmdText = &H1
Const adSchemaTables = 20, adSchemaColumns = 4
'1. получаем ID заказа:
Dim oArgs 'объекта для чтения параметров строки запуска файла
Set oArgs = WScript.Arguments 'получение объекта для чтения параметров строки запуска файла
Dim OrderID
OrderID = Trim(Replace(oArgs(0),"/","")) 'trim на всякий пожарный
'2. получаем путь к файлу
Dim oConMDB
Set oConMDB = CreateObject("ADODB.Connection")
'http://www.connectionstrings.com/access
With oConMDB
.Provider = "Microsoft.Jet.OLEDB.4.0"
.Open "D:\Documents\Склад и торговля\Backups\2012-01-13.mdb"
End With
Dim oRs, File
Set oRs = oConMDB.Execute("Select [FileEstimates] from [qdfOrders] Where ID = " & OrderID)
File = oRs("FileEstimates").Value
'3. открываем таблицу
Dim oConXLS
Set oConXLS = CreateObject("ADODB.Connection")
'http://www.connectionstrings.com/excel
With oConXLS
.Provider = "Microsoft.Jet.OLEDB.4.0"
.Properties("Extended Properties").Value = "Excel 8.0;IMEX=1;Hdr=Yes;Mode=Read;"
.CursorLocation = adUseClient
.Open File
End With
Dim oRsX
Set oRsX = oConXLS.Execute("Select * from [Общая$]")
Dim sSomeName, sUnit, sCalculatedQuantity, sAccompaniment, sManualAmount, sFactor, sTotalQuantity, sPrice, sTheCost,sOrderID
sOrderID = OrderID
'4. проходим по записям таблицы и забрасываем данные в MDB:
Do While Not (oRsX.EOF)
sSomeName = oRsX("Наименование").Value
sUnit = oRsX("Ед#из").Value
sCalculatedQuantity = oRsX("Расч#кол").Value
sPrice = oRsX("Цена").Value
sTheCost = oRsX("Стоимость").Value
sTotalQuantity = oRsX("Сум#кол").Value
sAccompaniment = oRsX("Сопутствие").Value
sManualAmount = oRsX("Ручн#кол").Value
sFactor = oRsX("К-ф").Value
Set oRs = oConMDB.Execute("INSERT INTO [tblEstimatedOrder] " & _
"(SomeName, Unit, CalculatedQuantity, Accompaniment, ManualAmount, Factor, TotalQuantity, Price, TheCost,OrderID
) " & _
"VALUES (CStr('" & sSomeName & "'), CStr('" & sUnit & "'), CDbl('" & sCalculatedQuantity & "'), CStr('" & sAccompaniment & "'), " & _
"CCur('" & sManualAmount & "'), CDbl('" & sFactor & "'), CDbl('" & sTotalQuantity & "'), CInt('" & sOrderID & "'),CCur('" & sPrice & "'),CCur('" & sTheCost & "'))")
oRsX.MoveNext
Loopвыкладываю ссылку на мою Б/Д
---------------------------
Ошибка при вычислении условия триггера
---------------------------
Ошибка -2147217904 в Условие триггера: Отсутствует значение для одного или нескольких требуемых параметров.Команда: SELECT TOP 1 1 FROM [qdfOrders] WHERE [FileEstimated] IS NOT NULL AND ID = 1
Условие: [FileEstimated] <> Null
---------------------------
ОК
---------------------------
Это косяк не скрипта, т.к. до его запуска дело даже не доходит.
Если убрать условие в триггере, то скрипт запускается и отрабатывает(с учётом ниже перечисленных замечаний). Так что ошибка возникает при проверке условия триггера. Кстати, зачем триггер привязан к удалению записи? При удалении заказа данные по заказу должны удаляться, а они наоборот добавятся повторно (если скрипт успеет отработать раньше чем будет удалена строка с ID и соответствющим FileEstimated, а если не успеет - будет ошибка при выполнении скрита, т.к. проверки на наличие данных я не делал).
В общем, нужно разбираться в самой программе, структуре и связи данных. Думаю стоит этим напрячь уже техподдержку программы(хотя бы на форуме).
Что до скрипта, то:
1. В стр. 51 имя колонки не совпадает с именем из экселя(ранее выложенный пример файла).
2. В стр. 55 разорвана строковая константа(после OrderID - перевод строки).
3. В запросе на добавление данных полная путаница - в поле Price БД добавляется ID заказа, в поле OrderID - что-то из денег(sTheCost). Данные перечисленные в VALUES должны идти в том-же порядке что и названия колонок в перечислении в начале запроса(INSERT INTO Statement (Microsoft Access SQL)).
P.S. многопользовательская система, понимаешь - хранить пароли юзеров плейнтекстом в незапароленной mdb-шке, это нечто ![]()
BeS Yara
Спасибо со всем разобрался, все получилось...
Есть еще одна задача, а как произвести экспорт из файла *.xls такого типа в таблицу tblDataCutting "Данные о раскрое"???
т.е. если в предыдущем разе мы экспортировали готовую таблицу, то в данном случае нужно выбрать выборочные значения из перевернутой таблицы
Данные из строки ''заказ'' нужно записать в поле OrderName
Данные из строки ''Материал'' нужно записать в поле Material
Данные из строки ''Дата'' нужно записать в поле DateIn
Данные из строки ''Размер плиты'' нужно записать в поле PlateSize
Данные из строки ''Количество плит материала'' нужно записать в поле AmountPlates
Добавление данных аналогично предидущему варианту. Отличие будет в получении данных из файла т.к.:
1. "*.xls такого типа" на самом деле не xls. Смена расширения не сделает из 2007-го экселя 2003-ий формат :)
2. Транспонированная таблица для ADO подходит слабо. Хотя(теоретически) что-то можно было бы придумать, но лучше попробовать организовать формирование таблицы в кошерном для последующей загрузки виде.
3. Данный файл это фактически архив(ZIP), содержащий набор документов(в основном XML). Так что вижу два возможных варианта работы с данным вариантом входного файла - использовать API Office2007(у меня такой возможности нет), или разбираться в формате файла и выдирать нужные данные из xml-ек. Если формат данный(число, расположение и "физический смысл" строк) всегда один и тотже(грубо говоря, размер плиты это ВСЕГДА ячейка B19), а лист всегда один, то достаточно наладить разбор XML-ки \xl\worksheets\sheet1.xml если нужны числовые данные, и добавочно \xl\sharedStrings.xml если нужны строковые данные.
Например, находим в sheet1.xml соответствующий нод(далее исключительно умозаключения на основе поверхностного анализа :), кто хочет знать Правду, тому путь в MSDN):
<row r="19" spans="1:3" x14ac:dyDescent="0.25">
<c r="A19" t="s">
<v>14</v>
</c>
<c r="B19" t="s">
<v>26</v>
</c>
</row>Насколько я понял, [t="s"] показывает что содержимое ячейки не число, точнее данные представленны как строка. Тот-же тип "s" идёт для ячейки с датой(которая после конвертирования в Excel2003 имеет общий формат). Если тип не указан, то в тэге v находится значение, если указан - индекс соответствующего нода в sharedStrings(может для нестроковых и не численных данных могут быть и другие хранилища - см. [Content_Types].xml).
Получаем индекс строки - 26.
Открываем sharedStrings.xml, находим 27-ой по счёту(индексы идут от нуля) элемент:
<si>
<t>2750x1830</t>
</si>Бинго :).
Можно, конечно анализировать ещё глубже - находить нужную строку по содержимому первой колонки, и искать соответствующие значения в остальных. Другими словами, писать полноценный парсер для офисного формата :)
С XML особо не работал, но на форуме были примеры работы с XML в vbs(для получения курсов валют с ЕЦБ мне сгодилось, с кое какими добавками из MSDN).
З.Ы. Если я правильно понимаю результаты поверхностного поиска по MSDN, то в отсутствии офиса с этим форматом(XLSX, ) вполне можно работать из .NET. В свете способов запуска импортирования данных(запуск программы по срабатыванию триггера), нет существенной разницы что будет запускаться - vbs или exe. Visual Studio Express бесплатна :)
З.З.Ы. Написал ответ.... Подумал... Нашел [MS-XLSX]: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Format. 291 страница тайного знания на языке оригинала(в PDF документе с водяным знаком "Предварительно", зато свежачёк: "Release: Sunday, January 22, 2012"). И, возможно, потребуются дополнительные источники информации. Пока времени на изучения этого талмуда у меня нет(как и насущной необходимости). Так что тут я пас.
BeS Yara
Привет !!!
Если формат данный(число, расположение и "физический смысл" строк) всегда один и тотже(грубо говоря, размер плиты это ВСЕГДА ячейка B19)
Да, это именно так
Мне еще подсказывают что можно пробоать так:
Sheets("Лист1").Range("A1").Value.но чет я не добился...
...еще в данном случае файл путь к файлу xls находится в таблице tblCuttingData поле CuttingFile
Мне еще подсказывают что можно пробоать так:
Sheets("Лист1").Range("A1").Value.но чет я не добился...
Для такого варианта:
1. На компьютере нужен установленный МС Офис(в случае ADO или разбора XML офис не требуется).
2. Для 2003-го офиса должен быть установлен конвертер файлов 2007-го офиса.
3. Файл должен иметь расширение соответствующее содержимому. В Вашем случае это не XLS, а XLSX.
' VB Script Document
Option Explicit
Dim objExcel
Set objExcel = WScript.CreateObject("Excel.Application")
With objExcel
With .Workbooks.Open("d:\aScripts\vbs\tmp\xl\РаскройИнфо.xlsx")
With .Sheets.Item(1)
wscript.echo .Range("B19").Value
End With
End With
.Quit
End With
Set objExcel = Nothingисточник: поиск по форуму("excel vbscript") => первая найденная тема, последний пост, вторая ссылка => 2-ое сообщение => 7 строк стереть, 1 добавить
Имейте ввиду, что при каждом запуске скрипта будет запускаться Excel. Если комп не сильно мощный, или уже много чего открыто, скрипт может работать не слишком быстро(на моём C2D P8600 @2.4GHz с 4Gb ОЗУ скрипт отрабатывает в среднем за 1.5-1.9 сек).
...еще в данном случае файл путь к файлу xls находится в таблице tblCuttingData поле CuttingFile
Это существенно? Если в tblCuttingData есть колонка ID, то в запросе меняется только название поля и название таблицы:
SELECT [Нужное поле] FROM [Нужная таблица] WHERE [колонка с ID] = [наш ID]BeS Yara
Для такого варианта:
1. На компьютере нужен установленный МС Офис(в случае ADO или разбора XML офис не требуется).
2. Для 2003-го офиса должен быть установлен конвертер файлов 2007-го офиса.
3. Файл должен иметь расширение соответствующее содержимому. В Вашем случае это не XLS, а XLSX.
Установлен офис 2010, при сохранении файла он открывается автоматически и выбор сохранкеия происходит вручную
Это существенно? Если в tblCuttingData есть колонка ID, то в запросе меняется только название поля и название таблицы:
В одном заказе может быть несколько типов материала
Установлен офис 2010, при сохранении файла он открывается автоматически и выбор сохранкеия происходит вручную
У меня установлен офис 2003, и при попытке открыть xlsx с расширением xls он выдаёт ошибку о неверном формате или повреждённом файле. При правильном расширении открывает нормально(правда появляется окошко при конвертации в формат 2003, но оно само закрывается по окончании). Так что если офис 2010 не на всех компьютерах где этот скрипт предполагается использовать, нужно иметь это ввиду.
В одном заказе может быть несколько типов материала
Значит помимо ID заказа нужно ещё добавлять ID материала:
SELECT [Нужное поле] FROM [Нужная таблица] WHERE [колонка с ID заказа] = [наш ID заказа] AND [колонка с ID материала] = [наш ID материала]BeS Yara
' VB Script Document Option Explicit Dim objExcel Set objExcel = WScript.CreateObject("Excel.Application") With objExcel With .Workbooks.Open("d:\aScripts\vbs\tmp\xl\РаскройИнфо.xlsx") With .Sheets.Item(1) wscript.echo .Range("B19").Value End With End With .Quit End With Set objExcel = Nothingисточник: поиск по форуму("excel vbscript") => первая найденная тема, последний пост, вторая ссылка => 2-ое сообщение => 7 строк стереть, 1 добавить
Пытался разобраться - не понял...:(
а как и куда вписать поля таблицы и путь к файлу раскроя ???
Пытался разобраться - не понял...:(
а как и куда вписать поля таблицы и путь к файлу раскроя ???
Не очень понял задачу - путь к файлу содержитсЯ в mdb или выбирается вручную оператором(кладовщиком, менеджером)?
В ранее выложенном образце БД путь к файлу содержится в таблице tblDataCutting, в которую предполагается сбрасывать данные - откуда там берётся путь когда там ещё нет материалов? Этот путь должен быть в таблице, в которой перечисляются материалы по данному заказу. Тогда по запросу к этой таблице по ID заказа и ID материала получаем список файлов(путей), которые необходимо импортировать в БД.
Например так::
1. Берёте код из поста #18.
2. Меняете запрос исходя из того где что хранится. В результате нужно будет получить таблицу из одного столбца - ID материала(допустим столбец называется MatID).
3. Вместо:
File = oRs("Notes").Valueвыполняем перебор полученных путей:
Do While Not (oRs.EOF)
Call InsertFromExcel(oRs(MatID).Value)
oRsX.MoveNext
Loopгде InsertFromExcel это процедура в которую включаем чтение значений из экселевского файла (пример в посте #24). Для каждого .Range("B19").Value(подставляем нужную ячейку вместо B19) вызываем проедуру вставки данных в mdb(процедуру создаём по примеру поста #18, 4-ый этап).
P.S. Интересно решить новую для себя проблему, разобраться с чем-то новым. Подсказать решение, в конце концов, особенно неочевидное для человека незнакомого с этой областью(сам иногда задаю вопросы). Но пережёвывать в пределах одной темы то что в ней уже есть - всякий интерес теряется. NecroTYN, мне кажется, Вам пора уже активно подключиться к решению Ваших задач.
' VB Script Document
option explicit
' константы для работы с ADO
Const adDouble = 5, adDate = 7, adCurrency = 6, adBoolean = 11, adVarWChar = 202, adLongVarWChar = 203
Const adUseClient = 3, adOpenStatic = 3, adLockOptimistic = 3, adCmdText = &H1
Const adSchemaTables = 20, adSchemaColumns = 4
'1. получаем ID заказа:
Dim oArgs 'объекта для чтения параметров строки запуска файла
Set oArgs = WScript.Arguments 'получение объекта для чтения параметров строки запуска файла
Dim OrderID
OrderID = Trim(Replace(oArgs(0),"/","")) 'trim на всякий пожарный
'2. получаем путь к файлу
Dim oConMDB
Set oConMDB = CreateObject("ADODB.Connection")
'http://www.connectionstrings.com/access
With oConMDB
.Provider = "Microsoft.Jet.OLEDB.4.0"
.Open "D:\Documents\Склад и торговля\Backups\2012-01-13.mdb"
End With
Dim oRs, File
Set oRs = oConMDB.Execute("SELECT [FileCutting] FROM [tblDataCutting] WHERE [OrderID] = [ID] from [qdfOrders]")
Do While Not (oRs.EOF)
Call InsertFromExcel(oRs(OrderID).Value)
oRsX.MoveNext
Loop
'3. открываем таблицу
Dim oConXLS
Set oConXLS = CreateObject("ADODB.Connection")
'http://www.connectionstrings.com/excel
With oConXLS
.Provider = "Microsoft.Jet.OLEDB.4.0"
.Properties("Extended Properties").Value = "Excel 8.0;IMEX=1;Hdr=Yes;Mode=Read;"
.CursorLocation = adUseClient
.Open File
End With
Sheets("Select * from [Панели для раскроя$]")
Dim sOrderName, sMaterial, sDateIn, sPlateSize, sAmountPlates
sOrderID = OrderID
'4. проходим по записям таблицы и забрасываем данные в MDB:
Option Explicit
Dim objExcel
Set objExcel = WScript.CreateObject("Excel.Application")
With objExcel
With .Workbooks.Open("d:\aScripts\vbs\tmp\xl\РаскройИнфо.xlsx")
With .Sheets.Item(1)
wscript.echo .Range("R1C1").Value
wscript.echo .Range("R2C2").Value
wscript.echo .Range("R3C2").Value
wscript.echo .Range("R19C2").Value
wscript.echo .Range("R20C2").Value
End With
End With
.Quit
End With
Set objExcel = Nothing
Do While Not (oRsX.EOF)
sOrderName = Range("R1C1").Value
sMaterial = Range("R2C2").Value
sDateIn = Range("R3C2").Value
sPlateSize = Range("R19C2").Value
sAmountPlates = Range("R20C2").Value
Set oRs = oConMDB.Execute("INSERT INTO [tblDataCutting] " & _
"(OrderName, Material, DateIn, PlateSize, AmountPlates) " & _
"VALUES (CStr('" & sOrderName & "'), CStr('" & sMaterial & "'), CDbl('" & sDateIn & "'), CStr('" & sPlateSize & "'), CCur('" & sAmountPlates & "'))")
oRsX.MoveNext
LoopВ общем колдовал -колдовал, наколдовал такой код, только не пашет..:(
Не очень понял задачу - путь к файлу содержитсЯ в mdb или выбирается вручную оператором(кладовщиком, менеджером)?
Данный момент происходит точно так же ккак и с файлом сметы
В одном заказе может быть несколько типов материала
Здесь имеется ввиду несколько типов материала для раскроя(соответственно и несколько файлов раскроя), их просто привязываем к заказу
P.S. Интересно решить новую для себя проблему, разобраться с чем-то новым. Подсказать решение, в конце концов, особенно неочевидное для человека незнакомого с этой областью(сам иногда задаю вопросы). Но пережёвывать в пределах одной темы то что в ней уже есть - всякий интерес теряется. NecroTYN, мне кажется, Вам пора уже активно подключиться к решению Ваших задач.
Я пытаюсь подключиться, но не всегда все могу понять
В общем колдовал -колдовал, наколдовал такой код, только не пашет..:(
Судя по всему, это Ваш первый опыт работы со скриптами. Нужно внимательно смотреть код и разбираться как он работает - метод копирования не всегда подходит, и ничему не учит. Иногда даже полезно переписать пример кода с нуля самому, по ходу дела разбираясь в нём. И знания получите, и, возможно, ошибки в примере обнаружите(кто пишет сходу и без багов - пусть первый бросит в меня камень
).
"SELECT [FileCutting] FROM [tblDataCutting] WHERE [OrderID] = [ID] from [qdfOrders]"Запрос ниочём, более того - второй FROM здесь это синтаксическая ошибка. Да и ID в запрос не подставлен.
Do While Not (oRs.EOF)
Call InsertFromExcel(oRs(OrderID).Value)
oRsX.MoveNext
LoopУсловие при переборе по oRs, а попытка перехода к следующей записи для рекордсета oRsX, который в Вашем скрипте даже не существует. Да и где, собственно, в приведённом коде процедура InsertFromExcel? Вы читаете сообщения об ошибках при запуске скрипта? Если программа подавляет сообщения об ошибках, запускайте скрипт с консоли передавая ей параметры вручную(естественно на тестовой базе). И никаких "On Error GoTo Next" кроме случаев когда это требуется для обработки ошибки в скрипте. Бездумное игнорирование ошибок делает работу скрипта непредсказуемой.
Смотрим далее: работаем с objExcel, выводим значения ячеек в консоль, закрываем эксель... А дальше попытка работать несуществующим рекордсетом(oRsX) закрытого объекта?
Опять не верно:
.Range("R1C1").ValueЕсли хочется обращаться к ячейки по номерам строки-колонки, то это делается иначе:
.Cells(1, 1).ValueВ экселе есть хэлп, запись макросов, отладчик - достаточно много источников информации по работе в VBA. Остальное можно уже искать в MSDN или поиском по интернету. Довольно редко встречаются уникальные, ранее не обсуждавшиеся в сети задачи.
Вот как примерно может выглядеть процедура InsertFromExcel. В неё нужно передавать путь к файлу раскроя. Также в процедуре понадобятся ID заказа(можно передавать в качестве параметра, а можно через заданную вне процедуры переменную OrderID):
Sub InsertFromExcel(file)
Dim objExcel
Set objExcel = WScript.CreateObject("Excel.Application")
Dim sOrderName, sMaterial, sDateIn, sPlateSize, sAmountPlates
With objExcel
With .Workbooks.Open(file)
With .Sheets.Item(1)
sOrderName = .Cells(1, 1).Value
sMaterial = .Cells(2, 2).Value
sDateIn = .Cells(3, 2).Value
sPlateSize = .Cells(19, 2).Value
sAmountPlates = .Cells(20, 2).Value
End With
End With
.Quit
End With
Set objExcel = Nothing
oConMDB.Execute "SQL-запрос на вставку/обновление данных"
End SubФинальный запрос:
Set oRs = oConMDB.Execute("INSERT INTO [tblDataCutting] " & _
"(OrderName, Material, DateIn, PlateSize, AmountPlates) " & _
"VALUES (CStr('" & sOrderName & "'), CStr('" & sMaterial & "'), CDbl('" & sDateIn & "'), CStr('" & sPlateSize & "'), CCur('" & sAmountPlates & "'))")Насчёт MDB не уверен, но в Trasact-SQL нет таких функций как CStr, CDbl, CCur и т.д. Приведение к нужному типу выполняйте в VB, или используйте Функции CAST и CONVERT (Transact-SQL).
Данный момент происходит точно так же ккак и с файлом сметы
В одном заказе может быть несколько типов материала
Полагаю дело обстоит так:
Есть заказ (tblOrders). Позиции заказа описываются в tblOrdersProducts (связь с tblOrders по [tblOrders].[ID]). Для позиций заказа не являющихся покупным изделием(условно) существует файл раскроя(видимо для расчёта стоимости затраченного материала, хотя пока это не существенно). Тогда пути к файлам раскроя должны быть в таблице tblOrdersProducts. А в tblDataCutting уже хранится информация из файлов раскроя для тех позиций заказа к которым это применимо. Связь должна быть с tblOrdersProducts по ID заказа и ID позиции в заказе(если бы там было что-то вроде uniqueidentifier для позиции заказа, можно было бы ограничиться им, но в mdb это недоступно).
Не вижу смысла добавлять в tblDataCutting кучу строк содержащих только пути, а потом обновлять эти строки данными из файла раскроя(хотя технически это и реализуемо, скорее всего). Или на одну позицию из заказа может быть несколько файлов раскроя? Тогда, конечно, хранение пути к файлу в таблице с раскроями, пожалуй, логично.
У меня сложилось впечатление что структура БД не продумывалась, а ваяется по ходу дела. Если я прав, то сначала нужно определиться с функционалом и продумать структуру таблиц, включая связи между ними. Если это начальный этап внедрения и есть специалист знающий VBA + SQL, то может даже стоит перейти на более гибкий вариант - MS Access + MS SQL Server(MSDE, Express - бесплатны, ограничения скорее всего окажутся не существенными). Причём Access нужен прежде всего разработчику - на рабочих местах можно обойтись Access Runtime.
...Или на одну позицию из заказа может быть несколько файлов раскроя?
Да, может - в одном заказе - изделии, может быть до 4х-5ти видов материала
....структура БД не продумывалась, а ваяется по ходу дела. Если я прав, то сначала нужно определиться с функционалом и продумать структуру таблиц, включая связи между ними. Если это начальный этап внедрения и есть специалист знающий VBA + SQL, то может даже стоит перейти на более гибкий вариант...
Здесь правда ваша !!!
я самостоятельно пытаюсь наладить функционал программы "Склад и торговля" под свои нужды, вот к сожалению специалистов знающих нет, вот и мучаю вас вопросами, сам пытаюсь разобраться но после 10-12 часового рабочего дня не в силах порой
Огромное спасибо за помощь
Полагаю дело обстоит так:Есть заказ (tblOrders). Позиции заказа описываются в tblOrdersProducts (связь с tblOrders по [tblOrders].[ID]). Для позиций заказа не являющихся покупным изделием(условно) существует файл раскроя
Файлы раскроя существуют не для позиций заказа, а для всего заказа, но их может быть несколько в зависимости от количества используемых материалов. Например есть заказ - Кухня, состоит она из следующих материалов(листовых и погонных) - Корпус-ЛДСП 1,Корпус-ЛДСП 2, Корпус-ДВПО, Столешница... Или может быть так: заказ на офисную мебель - Шкаф 1 -10шт
Шкаф 2 -5шт
Стол 2 -7шт
Тумба 7шт
Всего много а материал один, знач и файл раскроя 1
...Воот, и как правильно выставить связь ????:/:/:/
Сходу сложно предложить оптимальный вариант, но например так:
1. Таблица-справочник Материалы
ID | Наименование | Плотность | etc
2. Таблица МатериалыВЗаказах - для каждой позиции в заказе указываются используемые материалы:
ID | ID_Заказа | ID_ПозицииЗаказа | ID_ФайлыРаскроя | стол | ID(ЛДСП 1)
ID | ID_Заказа | ID_ПозицииЗаказа | ID_ФайлыРаскроя | стол | ID(ЛДСП 2)
ID | ID_Заказа | ID_ПозицииЗаказа | ID_ФайлыРаскроя | стол | ID(ДВПО)
ID | ID_Заказа | ID_ПозицииЗаказа | ID_ФайлыРаскроя | полка | ID(ЛДСП 1)
3. Таблица ФайлыРаскроя
ID | ID_Заказа | ПутьКФайлуРаскроя | etc
etc - дополнительные колонки(в примере привёл минимум).
В результате добавляем заказ(tblOrders), создаём его позиции(tblOrdersProducts) -стол, стул и т.д..
Для каждой позиции заказа из списка на основе справочника материалов указываем используемые материалы и заносим во вторую таблицу(кроме ID_ФайлыРаскроя).
Для заполнения третьей таблицы получаем список материалов по заказу для которых ID_ФайлыРаскроя пустой, назначаем файл раскроя для этого материала и его ID(который получится после добавления записи - не знаю есть ли возможность возврата ID после инсерта в MDB) записываем во вторую таблицу.
Если ничего не напутал, то такая структура позволит получать информацию о материалах, заказах/позициях заказа [не]использующих конкретный материал, файлах раскроя для заказов/материалов - в любой комбинации. Естественно для конкретного круга задач - есть и другие данные, и чтобы правильно их увязать нужно знать весь процесс который должен быть воплощён в БД(от заказа, до отгрузки клиенту - через заказа материалов, распределения материалов и задач по цехам, раскроям и прочей индивидуальной специфики конкретного пр-ва).
P.S. тема всё более смещается из концептуальной плоскости в сторону технической реализации конкретной(хотя и практически неописанной) технической задачи. Это требует значительно больше времени чем просто помощь советом, а свободного времени у меня мало. Подсказать какие-то моменты готов(в меру познаний и возможностей), тянуть проект - я пас.
Таблица МатериалыВЗаказах - для каждой позиции в заказе указываются используемые материалы
есть еще таблица Смета заказа, где отображаются все материалы используемые в заказе, видимо речь идет о ней...
' VB Script Document
option explicit
' константы для работы с ADO
Const adDouble = 5, adDate = 7, adCurrency = 6, adBoolean = 11, adVarWChar = 202, adLongVarWChar = 203
Const adUseClient = 3, adOpenStatic = 3, adLockOptimistic = 3, adCmdText = &H1
Const adSchemaTables = 20, adSchemaColumns = 4
'1. получаем ID заказа:
Dim oArgs 'объекта для чтения параметров строки запуска файла
Set oArgs = WScript.Arguments 'получение объекта для чтения параметров строки запуска файла
Dim OrderID
OrderID = Trim(Replace(oArgs(0),"/","")) 'trim на всякий пожарный
'2. получаем путь к файлу
Dim oConMDB
Set oConMDB = CreateObject("ADODB.Connection")
'http://www.connectionstrings.com/access
With oConMDB
.Provider = "Microsoft.Jet.OLEDB.4.0"
.Open "D:\Documents\Склад и торговля\Backups\2012-01-13.mdb"
End With
Dim oRs, File
Set oRs = oConMDB.Execute ("Select [FileCutting] from [tblDataCutting] Where OrderID = qdfOrders.ID ")
File = oRs("FileCutting").Value
Sub InsertFromExcel (File)
Dim objExcel
Set objExcel = WScript.CreateObject("Excel.Application")
Dim sOrderName, sMaterial, sDateIn, sPlateSize, sAmountPlates
With objExcel
With .Workbooks.Open(file)
With .Sheets.Item(1)
sOrderName = .Cells(1, 1).Value
sMaterial = .Cells(2, 2).Value
sDateIn = .Cells(3, 2).Value
sPlateSize = .Cells(19, 2).Value
sAmountPlates = .Cells(20, 2).Value
End With
End With
.Quit
End With
Set objExcel = Nothing
oConMDB.Execute ("Select [FileCutting] from [tblDataCutting] Where OrderID = qdfOrders.ID ")
End SubНИКАК:(
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться