VB6, EXCEL, no clipboard solution
От: ilya_ny  
Дата: 16.09.05 01:17
Оценка:
[это моя первая програма на VB6/EXCEL, так что может я вообще не в ту сторону смотрю]

на сервере создаются отчеты в виде EXCEL файлов (через Crystal Reports). один запрос — N EXCEL файлов (каждый файл имеет только 1 worksheet)
теперь хочется, чтобы это был ОДИН файл с N worksheets.
т.е. должна быть какая-то процедура, которая сливает N файлов в один с N worksheets.
мое рещение снизу и оно работает.
его недостаток — идет работа через clipboard и если другое приложение использует clipboard, то оно испортит работу этого.

Вопрос1: как написать эту процедуру БЕЗ использования clipboard?
Вопрос2: тот же что и Вопрос1, но без использования Excel API. может есть какая-то библиотека? например Crystal Reports не требует наличия EXCEL на сервере, а EXCEL файлы генерит.


спасибо!



    Private Sub merge_files()
        '== test data
        Dim files(10) As String
        
        files(1) = "C:\Temp\ExcelMerge\01.xls"
        files(2) = "C:\Temp\ExcelMerge\02.xls"
        files(3) = "C:\Temp\ExcelMerge\03.xls"
        files(4) = "C:\Temp\ExcelMerge\04.xls"
        files(5) = "C:\Temp\ExcelMerge\05.xls"
        files(6) = "C:\Temp\ExcelMerge\06.xls"
        files(7) = "C:\Temp\ExcelMerge\07.xls"
        files(8) = "C:\Temp\ExcelMerge\08.xls"
        files(9) = "C:\Temp\ExcelMerge\09.xls"
        files(10) = "C:\Temp\ExcelMerge\10.xls"
        
            
        Dim outputFileName As String
        outputFileName = "C:\Temp\ExcelMerge\merged.xls"
        
        '========================
        Dim excelApp As New excel.Application
         
        Dim wb_out As excel.Workbook
        Set wb_out = excelApp.Workbooks.Add
        
        For i = 1 To 10
            Dim wb As excel.Workbook
            Set wb = excelApp.Workbooks.Open(files(i))
            wb.Activate
            wb.Worksheets(1).Select
            wb.Worksheets(1).Cells.Select 'Cells.Select
            excelApp.Selection.Copy 'Selection.Copy
            
            wb_out.Activate
            If wb_out.Worksheets.Count < i Then
                wb_out.Worksheets.Add , wb_out.Worksheets(wb_out.Worksheets.Count)
            End If
            Dim ws_out As excel.Worksheet
            Set ws_out = wb_out.Worksheets(i)
            'ws_out.Select 'ws_out.Activate
            ws_out.Activate
            ws_out.Paste 'ActiveSheet.Paste
            ws_out.Range("A1:A1").Select
                                                          
            wb.Application.CutCopyMode = False
            wb.Close False
        Next i
                
        wb_out.SaveAs outputFileName
        excelApp.Quit
    End Sub
Re: VB6, EXCEL, no clipboard solution
От: Vi2 Удмуртия http://www.adem.ru
Дата: 16.09.05 08:09
Оценка: 2 (1)
Здравствуйте, ilya_ny, Вы писали:

_>т.е. должна быть какая-то процедура, которая сливает N файлов в один с N worksheets.

_>мое рещение снизу и оно работает.
_>его недостаток — идет работа через clipboard и если другое приложение использует clipboard, то оно испортит работу этого.

_>Вопрос1: как написать эту процедуру БЕЗ использования clipboard?


Для этого есть Move/Copy для Worksheet/Worksheets. В твоих обозначениях:
...
Set wb = excelApp.Workbooks.Open(files(i))
wb_out.Copy wb.Worksheets(1)
wb.Close False
...
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: VB6, EXCEL, no clipboard solution
От: Elena_ Россия  
Дата: 16.09.05 08:39
Оценка:
Здравствуйте, Vi2, Вы писали:


_>>Вопрос1: как написать эту процедуру БЕЗ использования clipboard?


Vi2>Для этого есть Move/Copy для Worksheet/Worksheets. В твоих обозначениях:

Vi2>
Vi2>...
Vi2>Set wb = excelApp.Workbooks.Open(files(i))
Vi2>wb_out.Copy wb.Worksheets(1)
Vi2>wb.Close False
Vi2>...
Vi2>


Единственно, что ячейки длиннее 255 обрезаются при копировании и с ними надо разбираться отдельно

_>>Вопрос2: тот же что и Вопрос1, но без использования Excel API. может есть какая-то библиотека? например Crystal _>>Reports не требует наличия EXCEL на сервере, а EXCEL файлы генерит.


Если число листов известно заранее или хотя бы ограниченно, то можно было бы заготовить пустой шаблон и подключаться к листам через ADO, кажется, так могло бы работать, хотя сама не пробовала
Пользователь — друг программиста!
Re[3]: VB6, EXCEL, no clipboard solution
От: ilya_ny  
Дата: 16.09.05 12:14
Оценка:
Здравствуйте, Elena_, Вы писали:


E_>Единственно, что ячейки длиннее 255 обрезаются при копировании и с ними надо разбираться отдельно

ну раз заранее неизвестно какие ячейки, то тогда со ВСЕМ ячейками надо разбираться отдельно

_>>>Вопрос2: тот же что и Вопрос1, но без использования Excel API. может есть какая-то библиотека? например Crystal _>>Reports не требует наличия EXCEL на сервере, а EXCEL файлы генерит.


E_>Если число листов известно заранее или хотя бы ограниченно, то можно было бы заготовить пустой шаблон и подключаться к листам через ADO, кажется, так могло бы работать, хотя сама не пробовала

я полумаю... только как мне кажется медленно будет работать
Re[4]: VB6, EXCEL, no clipboard solution
От: Elena_ Россия  
Дата: 16.09.05 20:02
Оценка:
Здравствуйте, ilya_ny, Вы писали:

E_>>Единственно, что ячейки длиннее 255 обрезаются при копировании и с ними надо разбираться отдельно

_> ну раз заранее неизвестно какие ячейки, то тогда со ВСЕМ ячейками надо разбираться отдельно

Move вроде бы не обрезает, только Copy

E_>>Если число листов известно заранее или хотя бы ограниченно, то можно было бы заготовить пустой шаблон и подключаться к листам через ADO, кажется, так могло бы работать, хотя сама не пробовала

_>я полумаю... только как мне кажется медленно будет работать

Никогда не пробовала, работает ли с листами Excel конструкция типа?
INSERT INTO ...
SELECT FROM ...


В принципе добраться до каких-то значений на листе Excel, по-моему, не медленнее ADO через SELECT чем средствами Excel, наверное, от конкретного алгоритма зависит
Пользователь — друг программиста!
Re[4]: Про ADO
От: ZAMUNDA Земля для жалоб и предложений
Дата: 16.09.05 23:13
Оценка:
Здравствуйте, ilya_ny, Вы писали:


_>>>>Вопрос2: тот же что и Вопрос1, но без использования Excel API.

А это что такое? Вот уж сколько лет с Excell работаю, но про API ихний не слышал, работал только через MS COM сервер и слыхал о библиотеке независимой, которая XL5 файлы делает.

_>>>> может есть какая-то библиотека? например Crystal _>>Reports не требует наличия EXCEL на сервере, а EXCEL файлы генерит.

Есть такая, но повторюсь, нашь программёр, работающий с ней, вещал что она только 5-ой версии xls'ы делает.

E_>>Если число листов известно заранее или хотя бы ограниченно, то можно было бы заготовить пустой шаблон и подключаться к листам через ADO, кажется, так могло бы работать, хотя сама не пробовала

DefaultDir'ом будет полный путь; DBQ — имя файла xls; таблица = имя листа. Эт я всё про параметры ConnectionString...
Лист должен (ну уж не знаю должен-ли, но по-крайней мере так работает точно) быть оформлен в виде списка, т.е. в первой строке в ячейках названия полей (столбцов), а ниже данные.

_>я полумаю... только как мне кажется медленно будет работать

Сдрасте! Это ж как это dll медленнее outproc COM сервера работать стала, позвольте осведомиться?
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re: VB6, EXCEL, no clipboard solution
От: ilya_ny  
Дата: 16.09.05 23:24
Оценка:
Здравствуйте, ilya_ny, Вы писали:


_>Вопрос1: как написать эту процедуру БЕЗ использования clipboard?


вот работающий пример если кому-то интересно
спасибо Vi2 за совет с методом Copy

перевел это на VB.NET и теперь ищу как закрыть EXCEL

Private Sub merge_files_copy()
        Dim files(10) As String
        
        files(1) = "C:\Temp\ExcelMerge\01.xls"
        files(2) = "C:\Temp\ExcelMerge\02.xls"
        files(3) = "C:\Temp\ExcelMerge\03.xls"
        files(4) = "C:\Temp\ExcelMerge\04.xls"
        files(5) = "C:\Temp\ExcelMerge\05.xls"
        files(6) = "C:\Temp\ExcelMerge\06.xls"
        files(7) = "C:\Temp\ExcelMerge\07.xls"
        files(8) = "C:\Temp\ExcelMerge\08.xls"
        files(9) = "C:\Temp\ExcelMerge\09.xls"
        files(10) = "C:\Temp\ExcelMerge\10.xls"
        
            
        Dim outputFileName As String
        outputFileName = "C:\Temp\ExcelMerge\merged.xls"
        
        '========================
        Dim excelApp As New Excel.Application
         
        Dim wb_out As Excel.Workbook
        Set wb_out = excelApp.Workbooks.Add
        
        '1. keep the worksheets number in the brand new Workbook (3 by default)
        Dim initialWorksheetNumber As Integer
        initialWorksheetNumber = wb_out.Sheets.Count
               
        '2. copy the 1st worksheet from each file to the result workbook
        For i = 1 To 10
            Dim wb As Excel.Workbook
            Set wb = excelApp.Workbooks.Open(files(i))
                   
            wb.Worksheets(1).Copy , wb_out.Sheets(wb_out.Sheets.Count)      
            
            wb.Close False
        Next i
        
        '3. delete the initial worksheets
        For i = 1 To initialWorksheetNumber
            Dim ws As Excel.Worksheet
            Set ws = wb_out.Worksheets(1)
            ws.Delete
        Next i
                
        wb_out.SaveAs outputFileName
        excelApp.Quit
    
End Sub
Re[2]: "excelApp.Quit" [-]
От: ZAMUNDA Земля для жалоб и предложений
Дата: 16.09.05 23:33
Оценка:
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[3]: "excelApp.Quit" [-]
От: ilya_ny  
Дата: 17.09.05 02:31
Оценка:
я не понял, то, что ты имел в виду

поиском по rsdn я нащел много на тему как закрыть excel, но он так и не закрывается..
Re[4]: "excelApp.Quit" [-]
От: ilya_ny  
Дата: 17.09.05 02:33
Оценка:
Здравствуйте, ilya_ny, Вы писали:

_>я не понял, то, что ты имел в виду


_> поиском по rsdn я нащел много на тему как закрыть excel, но он так и не закрывается..



кстати, именно и поэтому я хочу найти библиотеку, которая работает с excel без excel.application..

например написанная на чистом C# библиотека
Re[4]: А если так?
От: ZAMUNDA Земля для жалоб и предложений
Дата: 17.09.05 08:25
Оценка:
1) Отцепись от всех Excell'евских объектов.
2) После Quit отцепись от объекта Excell.

Вот пример:

Option Explicit

Public Sub Main()
    Dim clsXL As Excel.Application
    Dim clsWB As Excel.Workbook
    
    'После этой строчки запускется excel.exe
    Set clsXL = New Excel.Application
    Set clsWB = clsXL.Workbooks.Add
    
    'Книга закрыта но не выгрузилась из памяти.
    clsWB.Close SaveChanges:=False
    
    
    clsXL.Quit
    'ТОЛЬКО ПОСЛЕ этой строчки процесс excel.exe завершится.
    Set clsXL = Nothing
    
    'У меня лично, книга всё ещё не Nothing
    'правда и квойствам доступа нет и Excel.EXE тоже нет.
    'Всёравно такой ситуации лучше не допускать, т.к. при запущенном excell'е
    'до этой строчки, файл книги будет считаться открытым.
    Set clsWB = Nothing
End Sub
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[5]: А если так?
От: ilya_ny  
Дата: 17.09.05 12:33
Оценка:
Здравствуйте, ZAMUNDA, Вы писали:

ZAM>1) Отцепись от всех Excell'евских объектов.

ZAM>2) После Quit отцепись от объекта Excell.

в VB6 все с Quit прекрасно работает
а в VB.NET — нет. я все перепробовал как тут на сайте писали.. и ReleaseComObject вызываю и к Nothing присваиваю... не помогает

я думаю, что я в цикле получаю ссылки и не освобождаю их.. не знаю что делать
Re[6]: Делай на VBA/VB6
От: ZAMUNDA Земля для жалоб и предложений
Дата: 17.09.05 16:55
Оценка:
_>я думаю, что я в цикле получаю ссылки и не освобождаю их.. не знаю что делать
1)САБЖ. Я не из любителей кричать "да фуфло это дотнет", хотя к VB.Net антипатия имеется, просто если надо чтоб всё нормально работало, делай на VB6/VBA будет время разберёшся.

2) Запихни всё в библиотеку отдельную накрайняк и используй её. Можно вовсе извратиться, написать COM сервер и вызвать его из макроса -- IMHO наимаксимальнейшая скорость будет.
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[5]: VB6, EXCEL, no clipboard solution
От: Elena_ Россия  
Дата: 17.09.05 20:44
Оценка:
Здравствуйте, Elena_, Вы писали:

E_>Никогда не пробовала, работает ли с листами Excel конструкция типа?

E_>
E_>INSERT INTO ...
E_>SELECT FROM ...
E_>


E_>В принципе добраться до каких-то значений на листе Excel, по-моему, не медленнее ADO через SELECT чем средствами Excel, наверное, от конкретного алгоритма зависит


Вот так можно перетаскивать таблицы из одной книги в другую без Excel, не создавая заранее листы, а в процессе через Create Table


    Dim cnnSource As New ADODB.Connection, cnnDestin As New ADODB.Connection
    cnnSource.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                   "Data Source=K:\Xla\Source.xls;" & _
                   "Extended Properties=""Excel 8.0;HDR=Yes;"""
    cnnDestin.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                   "Data Source=K:\Xla\Destin.xls;" & _
                   "Extended Properties=""Excel 8.0;HDR=Yes;"""
             
    Dim sSQL As String
    Dim rstTables As New ADODB.Recordset, rstColumns As New ADODB.Recordset
    Dim rstSource As New ADODB.Recordset, rstDestin As New ADODB.Recordset
    Dim iField As Integer

    Set rstTables = cnnSource.OpenSchema(adSchemaTables)
    
    Dim sTableName As String, sColumnName As String, lColumnType As Integer, sColumnType As String
    While Not rstTables.EOF
        sTableName = rstTables!TABLE_NAME
        
        sSQL = "CREATE TABLE [" & Replace(sTableName, "$", "") & "] ("
        Set rstColumns = cnnSource.OpenSchema(adSchemaColumns, Array(Empty, Empty, sTableName))
        While Not rstColumns.EOF
            sColumnName = rstColumns!COLUMN_NAME
            lColumnType = rstColumns!DATA_TYPE
            Select Case lColumnType
            Case 5 ' DBTYPE_R8
                sColumnType = " DOUBLE"
            Case 130 ' DBTYPE_WSTR
                sColumnType = "char(" & rstColumns!CHARACTER_MAXIMUM_LENGTH & ")"
            Case Else
                MsgBox "?"
            End Select
        
            sSQL = sSQL & sColumnName & " " & sColumnType & ","
            
            rstColumns.MoveNext
        Wend
        rstColumns.Close
        Set rstColumns = Nothing
            
        sSQL = Left(sSQL, Len(sSQL) - 1) & ")"
        cnnDestin.Execute sSQL
        
        sSQL = "SELECT * FROM [" & sTableName & "]"
        rstSource.Open sSQL, cnnSource
        
        sSQL = "SELECT * FROM [" & sTableName & "]"
        rstDestin.Open sSQL, cnnDestin, adOpenKeyset, adLockOptimistic
                
        While Not rstSource.EOF
            rstDestin.AddNew
            For iField = 0 To rstSource.Fields.Count - 1
                rstDestin.Fields(iField) = rstSource.Fields(iField)
            Next iField
'''''            rstDestin.Update
            rstSource.MoveNext
        Wend
        rstDestin.UpdateBatch
        
        rstDestin.Close
        Set rstDestin = Nothing
        
        rstSource.Close
        Set rstSource = Nothing
        
        rstTables.MoveNext
    Wend
    rstTables.Close
    Set rstTables = Nothing
    
    cnnDestin.Close
    Set cnnDestin = Nothing
    
    cnnSource.Close
    Set cnnSource = Nothing


В принципе вроде бы не слишком медленно, конечно, от объема зависит

Пока не получилось типа
E_>
E_>INSERT INTO ...
E_>SELECT FROM ...
E_>


не берет строку второго подключения внутри запроса

Можно, конечно, приконнектить обе таблицы к mdb и перегнать пакетно, но тут уже непонятно, что оптимальнее.
Пользователь — друг программиста!
Re[6]: VB6, EXCEL, no clipboard solution
От: Elena_ Россия  
Дата: 17.09.05 21:36
Оценка:
Здравствуйте, Elena_, Вы писали:

E_>Пока не получилось типа

E_>>
E_>>INSERT INTO ...
E_>>SELECT FROM ...
E_>>


E_>не берет строку второго подключения внутри запроса


E_>Можно, конечно, приконнектить обе таблицы к mdb и перегнать пакетно, но тут уже непонятно, что оптимальнее.


А вот если привлечь еще и DAO, то получается

    Dim dbsDestin As DAO.Database
    Set dbsDestin = OpenDatabase("K:\Xla\Destin.xls", False, False, "Excel 8.0; HDR=YES;")


    sSQL = "INSERT INTO [" & sTableName & "] " & _
           "SELECT * FROM [" & sTableName & "] IN ""K:\xla\Source.xls"" ""Excel 8.0;;"""
               
    dbsDestin.Execute sSQL
    MsgBox dbsDestin.RecordsAffected


И выполняется совершенно моментально, на моем тесте, по крайней мере
Пользователь — друг программиста!
Re[7]: VB6, EXCEL, no clipboard solution
От: Elena_ Россия  
Дата: 17.09.05 21:51
Оценка: 3 (1)
Здравствуйте, Elena_, Вы писали:

E_>А вот если привлечь еще и DAO, то получается


E_>
E_>    Dim dbsDestin As DAO.Database
E_>    Set dbsDestin = OpenDatabase("K:\Xla\Destin.xls", False, False, "Excel 8.0; HDR=YES;")


E_>    sSQL = "INSERT INTO [" & sTableName & "] " & _
E_>           "SELECT * FROM [" & sTableName & "] IN ""K:\xla\Source.xls"" ""Excel 8.0;;"""
               
E_>    dbsDestin.Execute sSQL
E_>    MsgBox dbsDestin.RecordsAffected
E_>


E_>И выполняется совершенно моментально, на моем тесте, по крайней мере


На самом деле этот синтаксис и с ADO прекрасно работает, я почему-то с ADO пробовала другой синтаксис, он не пошел, а этот работает и с DAO и с ADO

То есть никакое DAO не нужно, а просто вместо переписывания Recordset, что несколько притормаживает
        sSQL = "INSERT INTO [" & sTableName & "] " & _
               "SELECT * FROM [" & sTableName & "] IN ""K:\xla\Source.xls"" ""Excel 8.0;;"""
               
        
        cnnDestin.Execute sSQL, lRecordsAffected
        MsgBox lRecordsAffected


Работает действительно очень прилично быстро
Пользователь — друг программиста!
Re[8]: VB6, EXCEL, no clipboard solution
От: ilya_ny  
Дата: 17.09.05 23:51
Оценка:
все классно

но, возвращаясь к исходной задаче, как создать новый worlsheet ?

мне нужно из N файлов создать 1 с N worksheets
Re[9]: VB6, EXCEL, no clipboard solution
От: Elena_ Россия  
Дата: 18.09.05 07:33
Оценка: 8 (1)
Здравствуйте, ilya_ny, Вы писали:

_>но, возвращаясь к исходной задаче, как создать новый worlsheet ?


_>мне нужно из N файлов создать 1 с N worksheets



Так CREATE TABLE как раз и создает новый worksheet с нужными столбцами, то есть полностью копирует структуру исходного листа, в этом коде достаточно менять Source, а Destin оставлять одним и тем же.

Конечно, проблема может возникнуть, если листы одинаково называются, тогда надо в CREATE TABLE добавить какой-нибудь суффикс или префикс с номером или что-то в этом роде

Вот последний вариант, вроде бы учитывает ячейки длиннее 255


    Dim cnnSource As New ADODB.Connection, cnnDestin As New ADODB.Connection
    cnnSource.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                   "Data Source=K:\Xla\Source.xls;" & _
                   "Extended Properties=""Excel 8.0;HDR=Yes;"""
    cnnDestin.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                   "Data Source=K:\Xla\Destin.xls;" & _
                   "Extended Properties=""Excel 8.0;HDR=Yes;"""
             
    Dim sSQL As String
    Dim rstTables As New ADODB.Recordset, rstColumns As New ADODB.Recordset
    Dim lRecordsAffected As Long
    Dim iField As Integer

    Set rstTables = cnnSource.OpenSchema(adSchemaTables)
    
    Dim sTableName As String, sColumnName As String, lColumnType As Integer, sColumnType As String
    While Not rstTables.EOF
        sTableName = rstTables!TABLE_NAME
        
        sSQL = "CREATE TABLE [" & Replace(sTableName, "$", "") & "] ("
        Set rstColumns = cnnSource.OpenSchema(adSchemaColumns, Array(Empty, Empty, sTableName))
        While Not rstColumns.EOF
            sColumnName = rstColumns!COLUMN_NAME
            lColumnType = rstColumns!DATA_TYPE
            Select Case lColumnType
            Case 5 ' DBTYPE_R8
                sColumnType = " DOUBLE"
            Case 130 ' DBTYPE_WSTR
''''''                sColumnType = "char(" & rstColumns!CHARACTER_MAXIMUM_LENGTH & ")"
                sColumnType = "memo" ' если больше 255
            Case Else
                MsgBox "?"
            End Select
        
            sSQL = sSQL & sColumnName & " " & sColumnType & ","
            
            rstColumns.MoveNext
        Wend
        rstColumns.Close
        Set rstColumns = Nothing
            
        sSQL = Left(sSQL, Len(sSQL) - 1) & ")"
        cnnDestin.Execute sSQL        ' создается новый Worksheet

        sSQL = "INSERT INTO [" & sTableName & "] " & _
               "SELECT * FROM [" & sTableName & "] IN ""K:\xla\Source.xls"" ""Excel 8.0;;"""
       
        cnnDestin.Execute sSQL, lRecordsAffected
        MsgBox lRecordsAffected
        
        rstTables.MoveNext
    Wend
    rstTables.Close
    Set rstTables = Nothing
    
    cnnDestin.Close
    Set cnnDestin = Nothing
    
    cnnSource.Close
    Set cnnSource = Nothing
Пользователь — друг программиста!
Re[10]: VB6, EXCEL, no clipboard solution
От: ilya_ny  
Дата: 18.09.05 20:38
Оценка:
Здравствуйте, Elena_, Вы писали:

спасибо, в в пнд. проверю
Re[10]: Всё намного проще.
От: ZAMUNDA Земля для жалоб и предложений
Дата: 19.09.05 12:45
Оценка: 20 (2)
Здравствуйте, Elena_, Вы писали:

E_>Здравствуйте, ilya_ny, Вы писали:


_>>но, возвращаясь к исходной задаче, как создать новый worlsheet ?


_>>мне нужно из N файлов создать 1 с N worksheets



E_>Так CREATE TABLE как раз и создает новый worksheet с нужными столбцами, то есть полностью копирует структуру исходного листа, в этом коде достаточно менять Source, а Destin оставлять одним и тем же.


E_>Конечно, проблема может возникнуть, если листы одинаково называются, тогда надо в CREATE TABLE добавить какой-нибудь суффикс или префикс с номером или что-то в этом роде


E_>Вот последний вариант, вроде бы учитывает ячейки длиннее 255


<поскипано>

Достаточно и половины доз... :) эээ... т.е. тут и одного Connection'а хватит. В моей задаче структура таблиц уже известна, так что если вдруг вам надо будет её получать, воспользуйтесь примером _Elena. Оговоюсь только, что Excell поддерживает такие типы данных:

CURRENCY
DATETIME
LOGICAL
NUMBER
TEXT


Короче, вот такие две книги:

'Макрос для Excell
Sub Макрос1()
    Dim clsWS As Excel.Worksheet
    
    Set clsWS = Application.Workbooks.Add().Sheets(1)
    
    With clsWS
        .Name = "People"
        .Range("A1").Value = "ID"
        .Range("B1").Value = "Name"
        .Range("A2").Value = 1
        .Range("B2").Value = "Коля"
        .Range("A3").Value = 2
        .Range("B3").Value = "Толя"
        .Range("A4").Value = 3
        .Range("B4").Value = "Витя"
    End With
    
    clsWS.Parent.Close True, "C:\Source1.xls"
    Set clsWS = Nothing
    
    Set clsWS = Application.Workbooks.Add().Sheets(1)
    
    With clsWS
        .Name = "People"
        .Range("A1").Value = "ID"
        .Range("B1").Value = "Name"
        .Range("A2").Value = 4
        .Range("B2").Value = "Маша"
        .Range("A3").Value = 5
        .Range("B3").Value = "Даша"
        .Range("A4").Value = 6
        .Range("B4").Value = "Катя"
    End With
    
    clsWS.Parent.Close True, "C:\Source2.xls"
End Sub

Следующий код из этих двух файлов создаёт третий с объединёнными данными из первых двух. Использовано "ADO 2.0".
Option Explicit

Public Const DB_DEFAULTDIR As String = "С:\"

Public Sub Main()
    Dim cnn As New ADODB.Connection
    Dim rss As ADODB.Recordset
    
    With cnn
        'DefaultDir можно любой путь, но он обязательно (кроме XL 3.0, 5.0) должен быть.
        .Open "DRIVER={Microsoft Excel Driver (*.xls)};DefaultDir=" & DB_DEFAULTDIR & ";READONLY=0"
        
        'Создаю книгу Excell.
        .Execute "CREATE TABLE [" & DB_DEFAULTDIR & "book_with_1sheet].[People] (ID NUMBER, Name TEXT(0))"
    
        'Можно сразу перекопировать.
        .Execute "INSERT INTO [" & DB_DEFAULTDIR & "book_with_1sheet].[People] SELECT * FROM [" & DB_DEFAULTDIR & "Source1].[People$]"
        
        'А можно и к созданному листу подключиться, чтоб в запросах полный путь не прописывать.
        'Это будет работать, только если READONLY=0 в ConnectionString!
        .DefaultDatabase = "book_with_1sheet"
        .Execute "INSERT INTO [People] SELECT * FROM [" & DB_DEFAULTDIR & "Source2].[People$]"
        
        'Пробую выбрать данные из новорожденной книги.
        Set rss = .Execute("SELECT T1.* FROM [People] T1")
        rss.Close
        
        'Создаю книгу Excell.
        .Execute "CREATE TABLE [" & DB_DEFAULTDIR & "book_with_2sheets].[People1] (ID NUMBER, Name TEXT(0))"
        .Execute "CREATE TABLE [" & DB_DEFAULTDIR & "book_with_2sheets].[People2] (ID NUMBER, Name TEXT(0))"
        
        'Подключаюсь к созданной книге.
        .DefaultDatabase = "book_with_2sheets"
        
        'Переношу данные.
        .Execute "INSERT INTO [People1] SELECT * FROM [" & DB_DEFAULTDIR & "Source1].[People$]"
        .Execute "INSERT INTO [People2] SELECT * FROM [" & DB_DEFAULTDIR & "Source2].[People$]"
        
        .Close
    End With
End Sub


Грабли:естественно файлов book_with_2sheets.xls и book_with_1sheet.xls не должно существовать.
Грабли:Строки при копировании обрезаются до 255 символов, эту проблемму я не решил... :( Правда, помнится, что-то говорилось, про "нерешаемость" в MSDN, но не помню где.


PS: Сразу у меня б спросили, зачем было огород городить... ;)
PPS: Ни капельки не хотел показывать некомпетентность _Elena.
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[11]: Всё намного проще.
От: Elena_ Россия  
Дата: 19.09.05 15:05
Оценка:
Здравствуйте, ZAMUNDA, Вы писали:

ZAM>PS: Сразу у меня б спросили, зачем было огород городить...

ZAM>PPS: Ни капельки не хотел показывать некомпетентность _Elena.

Больше решений, хороших и разных!
Пользователь — друг программиста!
Re[12]: BUG и благодарность.
От: ZAMUNDA Земля для жалоб и предложений
Дата: 19.09.05 15:30
Оценка:
Здравствуйте, Elena_, Вы писали:

E_>Больше решений, хороших и разных!

Благодарю за оценку.

Я пример не для папки 'C:\' писал, а поменял уже после того как код в сообщение вставил.... к чему я это? -- А!!!
Поменяйте
Public Const DB_DEFAULTDIR As String = "С:\"

на
Public Const DB_DEFAULTDIR As String = "C:\"


Кто непонял -- там русская 'ЭС' стоит, поменяйтен на английскую.
Простите за глюкавость.
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[13]: ADO решение и формат/стили
От: ilya_ny  
Дата: 20.09.05 01:23
Оценка:
Здравствуйте, Elena_, ZAMUNDA, Вы писали:

я попробовал ваши решения — спасибо!
Еленино, кстати, правильнее — оно учитывает db-схему исходного worksheet, хотя я все равно не смог застваить его работать на моих примерах буду дальше продолжать завтра.

я вот что думаю, а сохраняет это рещение стили/формат исходного worksheet.
например, если копируется A1 со значением 25 красного цвета на желтом фоне, то будет ли результирующий A1 red/yellow ?
Re[14]: 5 шапок из одной овцы не сделаешь
От: ZAMUNDA Земля для жалоб и предложений
Дата: 20.09.05 06:36
Оценка:
Здравствуйте, ilya_ny, Вы писали:

_>Здравствуйте, Elena_, ZAMUNDA, Вы писали:


_>я попробовал ваши решения — спасибо!

_>Еленино, кстати, правильнее — оно учитывает db-схему исходного worksheet, хотя я все равно не смог застваить его работать на моих примерах :) буду дальше продолжать завтра.
Непереставая испытывать чуство уважения&&восхищения к _Elena, скажу:
1) Плохо привязываться к конкретным версиям. Где гарантия, что этот запрос сработает на XL97?
sSQL = "INSERT INTO [" & sTableName & "] " & _
               "SELECT * FROM [" & sTableName & "] IN ""K:\xla\Source.xls"" ""Excel 8.0;;"""

Да и просто мои запросы читабельнее.
2) В аннотации к своему решению, я упомянул о том, что "ЕСЛИ ВДРУГ" понадобиться получать структуру таблицы то можно взять код у _Elena. Слово "вдруг" было не случайно вставлено ибо структура исходного листа должна быть (по-хорошему) известна в run-time. Потом объяснять начальнику почему половина сальдовки в сводный отчёт не попала сооовсем невесело.
Tip: я свои "регионы" приучил присылать отчёты в одном формате тремя рассылками с темой "Заполните приложенный документ пожалуйста" и приложенным XLS файлом с установленной защитой.
Тем более не вижу причин прописывать получение структуры таблицы, когда оно есть в предыдущем сообщении. К тому же у _Elena не учтены все типы данных, которые XL поддерживает (я кстати эти типы данных указал).
3) У меня не просто копируются данные из нескольких книг в одну, а СОЗДАЁТСЯ книга и в неё копируются данные из исходных двух.
4) Это наконецчёртподери пример, а не готовое приложение, его предназначение показать как то/это работает, а не сделать работу за вас.

_>я вот что думаю, а сохраняет это рещение стили/формат исходного worksheet.

_>например, если копируется A1 со значением 25 красного цвета на желтом фоне, то будет ли результирующий A1 red/yellow ?
Учитывая, сделанное ранее заявление о незапускаемости примера _Elena, предположу что у вас просто не установлен Excell. -- Установите Excell и всё попробуйте сами. ;)
Вообщето ADO призвано заниматься передачей данных между клиентом и БД, форматирование в Excell под эту статью не подходит.
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[14]: ADO решение и формат/стили
От: Elena_ Россия  
Дата: 20.09.05 08:27
Оценка:
Здравствуйте, ilya_ny, Вы писали:

_>Еленино, хотя я все равно не смог застваить его работать на моих примерах буду дальше продолжать завтра.


А что именно не работает?

_>я вот что думаю, а сохраняет это рещение стили/формат исходного worksheet.

_>например, если копируется A1 со значением 25 красного цвета на желтом фоне, то будет ли результирующий A1 red/yellow ?

Конечно, только данные переносятся, оформление к ADO не относится.
Пользователь — друг программиста!
Re[15]: ADO решение и формат/стили
От: ilya_ny  
Дата: 20.09.05 11:33
Оценка:
Здравствуйте, Elena_, Вы писали:

_>>Еленино, хотя я все равно не смог застваить его работать на моих примерах

E_>А что именно не работает?
я может позже выложу пример — мне надо его подчистить

_>>я вот что думаю, а сохраняет это рещение стили/формат исходного worksheet.

_>>например, если копируется A1 со значением 25 красного цвета на желтом фоне, то будет ли результирующий A1 red/yellow ?
E_>Конечно, только данные переносятся, оформление к ADO не относится.
но тогда это, к сожалению, не подходит

у меня каждый excel-файл — это красивый сгенерированный форматированный отчет.
если не копировать стили, то тогда это все не имеет смысла..

а исходная идея была такая — каждый месяц — это отчет
12 файлов неохота держать — хочется один с 12 worksheets
каждый worksheet — название месяца

пока я вижу выход:
1. установить Excel на сервер
2. COM — объект из VB6 кода который работает (он excel убивает) (1/10000 всего проекта)
3. .NET будет вызывать этот COM
корявое временное рещение
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.