Сейчас мы с Вами рассмотрим пример реализации того, как можно выполнить слияние данных Word с данными Microsoft SQL Server, при этом данный процесс будет автоматизирован средствами VBA Access 2003.
Многие, наверное, уже умеют осуществлять слияние документов Word, например, с источником данных Excel или с тем же SQL сервером, но не все знают, как можно автоматизировать данный процесс или внедрить его в какую-нибудь программу.
Однажды у меня встала задача автоматизировать слияние некого шаблона Word с данными расположенными на SQL сервере, при этом все это необходимо было внедрить в программу, разработанную в Access 2003 (ADP проект). И сегодня я покажу пример решения данной задачи.
Содержание
- Исходные данные
- Создаем файл подключения к источнику данных MS SQL Server
- Создаем шаблон Word для слияния
- Код VBA Access 2003 для слияния документа Word с источником данных MS SQL Server
Исходные данные
И для начала давайте разберем исходные данные, т.е. что мы имеем.
Итак, в качестве клиента, как я уже сказал, у нас будет выступать ADP проект Access 2003. В качестве источника данных для примера будет выступать SQL Server 2012 Express. На компьютере установлен Microsoft Office 2013 (и Access 2003).
Создадим на сервере тестовую таблицу и заполним ее данными (допустим в базе данных Test). Для этого Вы можете запустить следующую SQL инструкцию.
Заметка! Начинающим программистам рекомендую почитать книгу «SQL код», с помощью которой Вы научитесь работать с языком SQL во всех популярных системах управления базами данных.
CREATE TABLE dbo.TestTable( ID INT IDENTITY(1,1) NOT NULL, ProductName VARCHAR(50) NOT NULL, Price MONEY NULL, CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED (ID ASC) ) GO INSERT INTO dbo.TestTable(ProductName, Price) VALUES ('Компьютер', 500) GO INSERT INTO dbo.TestTable(ProductName, Price) VALUES ('Монитор', 400) GO INSERT INTO dbo.TestTable(ProductName, Price) VALUES ('Телефон', 200) GO INSERT INTO dbo.TestTable(ProductName, Price) VALUES ('Планшет', 300) GO INSERT INTO dbo.TestTable(ProductName, Price) VALUES ('Принтер', 250) GO SELECT * FROM TestTable
Заметка! Если Вы не знаете, что делает вышеуказанная инструкция, рекомендую посмотреть мой видеокурс «T-SQL. Путь программиста от новичка к профессионалу. Уровень 1 – Новичок», который предназначен для начинающих. В нем подробно рассмотрены все базовые конструкции языка SQL, включая все вышеперечисленные.
Теперь давайте создадим файл подключения (ODC) к нашему источнику данных. Данный файл будет выступать своего рода «шаблоном файла подключения», так как впоследствии мы можем, и будем переопределять и базу данных и сам SQL запрос.
Для создания файла подключения к SQL серверу давайте откроем Word и стандартным способом создадим данный файл, т.е. с помощью функционала «Рассылки». (Кстати пример создания подключения к SQL серверу из Excel мы с Вами уже рассматривали в материале – Excel — Подключение и получение данных с SQL сервера).
Переходим на вкладку рассылки и в меню «Выбрать получателей» выбираем «Использовать существующий список».
Затем в окне выбора источника данных нажимаем кнопку «Создать».
Далее выбираем тип источника данных, т.е. Microsoft SQL Server. Жмем «Далее».
Потом вводим адрес сервера и нажимаем «Далее».
Затем выбираем базу данных и таблицу для подключения, еще раз напомню, это всего лишь шаблон, все эти параметры мы будем переопределять, жмем «Далее».
И в заключение вводим понятное название файла подключения, а также мы можем сразу его сохранить в нужный нам каталог путем кнопки «Обзор», по умолчанию он сохраняется в «C:UsersИмя_ПользователяDocumentsМои источники данных». Нажимаем «Готово».
Все, файл создан, Word можем закрыть без сохранения.
Создаем шаблон Word для слияния
Теперь давайте подготовим шаблон Word, т.е. это тот документ, в который мы будем подставлять данные из базы данных SQL сервера.
Вся подготовка сводится к тому, что нам необходимо вставить поля слияния там, где это нам нужно. Это делается следующим образом. Вкладка «Вставка -> Экспресс-блоки -> Поле».
Ищем поле MERGEFIELD и вводим название поля, которое будет соответствовать полю в источнике данных (в моем случае это ProductName и Price). Жмем «ОК».
Так как у меня это тестовый шаблон в нем текста практически не будет, и выводить я буду всего два поля, у Вас скорей всего будет много текста и много полей слияния.
Код VBA Access 2003 для слияния документа Word с источником данных MS SQL Server
Осталось написать код VBA, который будет осуществлять слияние. Для примера давайте добавим на форму кнопку StartMerge и поле Price для фильтрации данных. Затем в редакторе Visual Basic напишем процедуру для слияния, допустим с названием MergeWord, и в обработчик события кнопки StartMerge (нажатие кнопки) вставляем код вызова этой процедуры. Весь код будет выглядеть следующим образом (я его прокомментировал). Сразу поясню, что шаблон Word и файл ODC у меня лежат в каталоге D:Test.
'Процедура для запуска слияния Private Sub MergeWord(TemplateWord As String, QuerySQL As String) 'Первый параметр - Путь к шаблону Word 'Второй параметр - Строка запроса к БД On Error GoTo Err1 Dim ConnectString As String, PathOdc As String Dim WordApp As Object Dim WordDoc As Object 'Шаблон файла ODC для подключения к данным PathOdc = "D:TestTestSourceData.odc" If TemplateWord <> "" Then 'Создаем документ Word Set WordDoc = CreateObject("Word.document") Set WordDoc = GetObject(TemplateWord) Set WordApp = WordDoc.Parent 'Создаём подключение к источнику данных (MS SQL Server) 'Некоторые данные берём из текущего подключения ADP проекта ConnectString="Provider=SQLOLEDB.1; " & _ "Integrated Security=SSPI;" & _ "Persist Security Info=True; " & _ "Initial Catalog=" & CurrentProject.Connection.Properties("Initial Catalog") & "; " & _ "Data Source=" & CurrentProject.Connection.Properties("Data Source") & "; " & _ "Use Procedure for Prepare=1;" & _ "Auto Translate=True;" & _ "Packet Size=4096;" & _ "Use Encryption for Data=False;" 'Задаем источник данных WordDoc.MailMerge.OpenDataSource NAME:=PathOdc, _ Connection:=ConnectString, _ SQLStatement:=QuerySQL 'Делаем видимым Word WordApp.Visible = True WordApp.Activate 'Начинаем слияние With WordDoc.MailMerge .Destination = wdSendToNewDocument .SuppressBlankLines = True .Execute Pause:=False End With 'Закрываем шаблон без сохранения WordDoc.close (wddonotsavechanges) Set WordDoc = Nothing Set WordApp = Nothing Else MsgBox "Не указан шаблон для слияния", vbCritical, "Ошибка" End If Ex1: Exit Sub Err1: MsgBox Err.Description WordDoc.close (wddonotsavechanges) WordApp.Quit Set WordDoc = Nothing Set WordApp = Nothing Resume Ex1 End Sub Private Sub StartMerge_Click() Dim Filter As String Filter = "" 'Условие If Nz(Me.Price, "") <> "" Then Filter = "WHERE Price >= " & Me.Price End If 'Вызов процедуры слияния Call MergeWord("D:TestШаблон.docx", "SELECT * FROM ""TestTable"" " & Filter & " ") End Sub
Сохраняем и проверяем работу.
После нажатия на кнопку (StartMerge) запустится Word, в котором уже все данные заполнены и документов будет столько, сколько строк в источнике.
Как видим, все работает. На этом у меня все, надеюсь, материал был полезен. Пока!
Спасибо, я попробую
Добавлено через 1 час 13 минут
Попробовал не получилось
Добавлено через 1 час 58 минут
Помогитеее!!!!
Добавлено через 10 часов 5 минут
Я на сайте connectionstrings.com нашёл следующие варианты подключения к Exel 2007 (ACE OLEDB 12.0).
Для моего случая наверно надо использовать первый вариант. Подскажите как правильно это сделать. Я пробовал у меня не получилось.
Connection strings for Excel 2007 (ACE OLEDB 12.0)
Type: OLE DB Provider
Usage: Provider=Microsoft.ACE.OLEDB.12.0
Xlsx files
This one is for connecting to Excel 2007 files with the Xlsx file extension. That is the Office Open XML
format with macros disabled.
Код
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyExcel2007file.xlsx;Extended Properties="Excel 12.0 Xml;HDR=YES";
«HDR=Yes;» indicates that the first row contains columnnames, not data. «HDR=No;» indicates the opposite.
Treating data as text
Use this one when you want to treat all data in the file as text, overriding Excels column type
«General» to guess what type of data is in the column.
Код
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyExcel2007file.xlsx;Extended Properties="Excel 12.0 Xml;HDR=YES;IMEX=1";
If you want to read the column headers into the result set (using HDR=NO even though there is a header) and
the column data is numeric, use IMEX=1 to avoid crash.
To always use IMEX=1 is a safer way to retrieve data for mixed data columns. Consider the scenario that one
Excel file might work fine cause that file’s data causes the driver to guess one data type while another
file, containing other data, causes the driver to guess another data type. This can cause your app to
crash.
Xlsb files
This one is for connecting to Excel 2007 files with the Xlsb file extension. That is the Office Open XML
format saved in a binary format. I e the structure is similar but it’s not saved in a text readable format
as the Xlsx files and can improve performance if the file contains a lot of data.
Код
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyBinaryExcel2007file.xlsb;Extended Properties="Excel 12.0;HDR=YES";
You can also use this connection string to connect to older 97-2003 Excel workbooks.
«HDR=Yes;» indicates that the first row contains columnnames, not data. «HDR=No;» indicates the opposite.
Xlsm files
This one is for connecting to Excel 2007 files with the Xlsm file extension. That is the Office Open XML
format with macros enabled.
Код
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyExcel2007file.xlsm;Extended Properties="Excel 12.0 Macro;HDR=YES";
Important note!
The quota » in the string needs to be escaped using your language specific escape syntax.
c#, c++ «
VB6, VBScript «»
xml (web.config etc) "
or maybe use a single quota ‘.
«HDR=Yes;» indicates that the first row contains columnnames, not data. «HDR=No;» indicates the opposite.
rikomono
Интересующийся |
Помогите написать макрос. Добавлено через 1 час, 14 минут и 59 секунд: (click to show) Sub Trans() Добавлено через 10 минут и 16 секунд: |
||
|
HandKot
Молодой специалист
|
примерно так, но, скажу сразу, макрос не работает Public Sub test() ‘открываем соединение к БД ‘бежим по всем словам в тексте ‘Слово находящееся в ячейке поля «ВВВ» справа от слова в поле «ААА» было помещено на слово в исходном тексте с помощью (PhoneticGuide ‘ А если слова нет в базе данных, то слово в тексте заключалось бы в такие скобки <слово> Set rs = Nothing |
||
I Have Nine Lives You Have One Only |
rikomono
Интересующийся |
примерно так, но, скажу сразу, макрос не работает Спасибо. Пойду искать напильник, если мозгов хватит Добавлено через 11 часов, 21 минуту и 9 секунд: примерно так, но, скажу сразу, макрос не работает Мне помогли, написали вот такой макрос, но он тоже не работает http://narod.ru/disk/14632215001/%D0%90%D0%90%D0%90.rar.html |
||
|
rikomono
Интересующийся |
Public Sub test() ‘открываем соединение к БД ‘бежим по всем словам в тексте ‘Слово находящееся в ячейке поля «ВВВ» справа от слова в поле «ААА» было помещено на слово в исходном тексте с помощью (PhoneticGuide ‘ А если слова нет в базе данных, то слово в тексте заключалось бы в такие скобки <слово> Set rs = Nothing Мне сказали, что в последнем куске кода не указана строка подключения к базе данных. А ещё для работоспособности указанного куска кода необходимо подключить к проекту VBA одну из версий библиотеки Microsoft ActiveX Data Objects. Определись, в каком формате база данных, где она находится (путь к файлу базы данных). |
||
|
RXL
Технический
|
rikomono, сразу видно, что ты даже не прочитал, что тебе написали… cn.ConnectionString = «тута строка подключения» |
||
… мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |
rikomono
Интересующийся |
rikomono, сразу видно, что ты даже не прочитал, что тебе написали… cn.ConnectionString = «тута строка подключения» Нет я прочитал вписал туда адрес базы. Вписывал туда адрес документа Ехеl затем вписывал адрес базы Access, так и так не работает. Вылетает ошибка (Compile error: User-defined type not defined) (click to show) Public Sub test() ‘открываем соединение к БД ‘бежим по всем словам в тексте ‘Слово находящееся в ячейке поля «ВВВ» справа от слова в поле «ААА» было помещено на слово в исходном тексте с помощью (PhoneticGuide ‘ А если слова нет в базе данных, то слово в тексте заключалось бы в такие скобки <слово> Set rs = Nothing и пробовал вот так (click to show) Public Sub test() ‘открываем соединение к БД ‘бежим по всем словам в тексте ‘Слово находящееся в ячейке поля «ВВВ» справа от слова в поле «ААА» было помещено на слово в исходном тексте с помощью (PhoneticGuide ‘ А если слова нет в базе данных, то слово в тексте заключалось бы в такие скобки <слово> Set rs = Nothing Добавлено через 41 минуту и 53 секунды: |
||
|
rikomono
Интересующийся |
Спасибо за информацию. Я почитал. (click to show) Connection strings for Excel 2007 (ACE OLEDB 12.0) Xlsx files Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyExcel2007file.xlsx;Extended Properties=»Excel 12.0 Xml;HDR=YES»; «HDR=Yes;» indicates that the first row contains columnnames, not data. «HDR=No;» indicates the opposite. Treating data as text Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyExcel2007file.xlsx;Extended Properties=»Excel 12.0 Xml;HDR=YES;IMEX=1″; If you want to read the column headers into the result set (using HDR=NO even though there is a header) and the column data is numeric, use IMEX=1 to avoid crash. To always use IMEX=1 is a safer way to retrieve data for mixed data columns. Consider the scenario that one Excel file might work fine cause that file’s data causes the driver to guess one data type while another file, containing other data, causes the driver to guess another data type. This can cause your app to crash. Xlsb files Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyBinaryExcel2007file.xlsb;Extended Properties=»Excel 12.0;HDR=YES»; You can also use this connection string to connect to older 97-2003 Excel workbooks. «HDR=Yes;» indicates that the first row contains columnnames, not data. «HDR=No;» indicates the opposite. Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyExcel2007file.xlsm;Extended Properties=»Excel 12.0 Macro;HDR=YES»; Important note! «HDR=Yes;» indicates that the first row contains columnnames, not data. «HDR=No;» indicates the opposite. Для моего случая наверно надо использовать первый вариант. Подскажите как правильно это сделать. Я пробовал у меня не получилось |
||
|
RXL
Технический
|
1. MS Office 2007 у тебя стоит? |
||
… мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |
rikomono
Интересующийся |
Да у меня MS Office 2007. (click to show) Public Sub test() ‘открываем соединение к БД ‘бежим по всем словам в тексте ‘Слово находящееся в ячейке поля «ВВВ» справа от слова в поле «ААА» было помещено на слово в исходном тексте с помощью (PhoneticGuide ‘ А если слова нет в базе данных, то слово в тексте заключалось бы в такие скобки <слово> Set rs = Nothing И ещё наверно вот в этом месте If Asc(w.Text) > 30 Then w.PhoneticGuide Text:=»qqq», Alignment:=wdPhoneticGuideAlignmentOneTwoOne, Raise:=14, FontSize:=10, FontName:=»Lucida Sans Unicode» Вместо «qqq» должно стоять » + w.Text + » наверно? |
||
|
RXL
Технический
|
Гадать лучше всего на кофейной гуще. И бубен нужен настоящий, шаманский. Если пишешь на языке, то изучи сперва его синтаксис! Когда в текст нужно вставить двойную кавычку, ее следует удвоить. x = «aaaa»«bbbb»«» |
||
… мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |
rikomono
Интересующийся |
Гадать лучше всего на кофейной гуще. И бубен нужен настоящий, шаманский. Если пишешь на языке, то изучи сперва его синтаксис! Я не гадаю на кофейной гуще, я просто не знаю VBA, но мне очень нужен этот макрос. Я для дочери делаю фонетическое руководство. Вот и пришёл на форум программистов за помощью. |
||
|
RXL
Технический
|
rikomono, эх, вот воя строчка: cn.ConnectionString = «Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:AAA.xlsx;Extended Properties=»»Excel 12.0 Xml;HDR=YES»»;» Макрос твой хреновый и работать не будет. Тут еще горы несуразностей.
Строчку 20, полагаю, надо пеместить на 15-ю позицию. |
||
… мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |
HandKot
Молодой специалист
|
Строчку 20, полагаю, надо пеместить на 15-ю позицию. это точно скажу сразу, что не получилось For i = 1 To ThisDocument.Words.Count на обратный ход, но точной уверенности нет |
||
I Have Nine Lives You Have One Only |
rikomono
Интересующийся |
Макрос твой хреновый и работать не будет. Тут еще горы несуразностей. Да Вы правы он не работает, но вот посмотрите вот этот он почти работает +++.rar,запустить макрос start при первом запросе надо открыть базу Exel при втором базу Access (он работает только если каждое слово на новой строке). Как бы сделать так, чтобы макрос start производил операцию (PhoneticGuide) в обычном тексте, а не когда каждое слово на отдельной строке. |
||
|
RXL
Технический
|
rikomono, трудно понять, читаешь ли ты, что мы тебе пишем. Короче, вот, что коллективный разум предложил:
Мне только не понятен смысл « Asc(w.Text) > 30 » в строке 17. |
||
… мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |
rikomono
Интересующийся |
RXL, у меня вопрос, а макрос который Вы предложили у Вас работает? |
||
|
RXL
Технический
|
Я его не проверял. Непонятное я указал постом выше — остальное очевидно. |
||
… мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |
HandKot
Молодой специалист
|
Мне только не понятен смысл «Asc(w.Text) > 30» в строке 17. а это чтобы он не обрабатывал спец символы они вроде как отдельное слово или я что-то путаю У меня он не работает он работает, только что проверил, но надо доработать напильником |
||
I Have Nine Lives You Have One Only |
Fedor
Новенький |
Господа мне тоже нужен такой код! |
||
|
Dimka
Деятель
|
Fedor, надо подключить COM-объект. Как — не скажу, MSO давно уже под рукой нет. |
||
Программировать — значит понимать (К. Нюгард) |
HandKot
Молодой специалист
|
выдаёт ошибку User-defined type not defined и показывает на «cn As New ADODB.Connection» из четвертой строки. либо подключите библиотеку Microsoft ActiveX Data Objects x.x Library Dim cn As Object |
||
I Have Nine Lives You Have One Only |