Помощь - Поиск - Пользователи - Календарь
Полная версия: Delphi и Excel
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Делфи
Atreides
Впервые в жизни столкнулся с такой задачкой, посмотрел на подобе вроде нету. Мне нужно выдернуть данные из ексельного файла со сложной структурой данные, которые могут быть не нормированы, т.е. не ограниченны по длине. Запись произвести в стринггрид или дбгрид. Нужны следующие поля А 5 или 10, т.е. те в которых есть надпись НОД 3, все D с названиями, причем коды нужно писать отдельно, все H соответствующие D, и все B с датами месяца и года в разные ячейки. Пробовал фильтрами, но это только отсеивает, а не прописывает. Надо прописать, что бы после можно было портировать данные эти в ораклинную базу. Меня еще останавливает, то что нельзя задать ячейки железно, на тот случай, если таблица пополнится новыми позициями
volvo
Я, может, чего-то не понимаю, но если ты знаешь, что в ячейке A5 находится текст "НОД 3", зачем тебе читать это поле? Я тебе и так скажу, что оно содержит. Не поверишь, но оно содержит "НОД 3".

Цитата
все D с названиями
Ну, и проходи по ячейкам "D1" .. "Dдо_посинения", проверяй на пустоту и если не пусто - то нашел, что тебе нужно, можешь отсекать все после последнего пробела и делить информацию на Название и Код. Поскольку при этом ты знаешь номер строки, из которой это все читалось, то элементарно вытягивается содержимое соответствующих полей из столбцов B и H. В чем проблема, я не пойму?

Оракла не держу. Если интересно - могу набросать программу, которая из присоединенного тобой файла выдерет всю нужную информацию (Название/Код/Что_там_у_тебя_в_столбце_B/Дебет), и занесет ее в StringGrid на форме, или в базу MS Access... Только что там с A5/A10 - надо бы уточнить...
Atreides
Я писал вот так...
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Grids, DBGrids, Menus, ComObj;
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
StringGrid1: TStringGrid;
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
Button1: TButton;
Button2: TButton;
procedure N3Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function Xls_To_StringGrid(AGrid: TStringGrid; AXLSFile: string): Boolean;
const
xlCellTypeLastCell = $0000000B;
var
XLApp, Sheet: OLEVariant;
RangeMatrix: Variant;
x, y, k, r: Integer;
begin
Result := False;
// Create Excel-OLE Object
XLApp := CreateOleObject('Excel.Application');
try
// Hide Excel
XLApp.Visible := False;
// Open the Workbook
XLApp.Workbooks.Open(AXLSFile);
// Sheet := XLApp.Workbooks[1].WorkSheets[1];
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];
// In order to know the dimension of the WorkSheet, i.e the number of rows
// and the number of columns, we activate the last non-empty cell of it
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
// Get the value of the last row
x := XLApp.ActiveCell.Row;
// Get the value of the last column
y := XLApp.ActiveCell.Column;
// Set Stringgrid's row &col dimensions.
AGrid.RowCount := x;
AGrid.ColCount := y;
// Assign the Variant associated with the WorkSheet to the Delphi Variant
RangeMatrix := XLApp.Range['A1', XLApp.Cells.Item[X, Y]].Value;
// Define the loop for filling in the TStringGrid
k := 1;
repeat
for r := 1 to y do
AGrid.Cells[(r - 1), (k - 1)] := RangeMatrix[K, R];
Inc(k, 1);
AGrid.RowCount := k + 1;
until k > x;
// Unassign the Delphi Variant Matrix
RangeMatrix := Unassigned;
finally
// Quit Excel
if not VarIsEmpty(XLApp) then
begin
// XLApp.DisplayAlerts := False;
XLApp.Quit;
XLAPP := Unassigned;
Sheet := Unassigned;
Result := True;
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Close;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if Xls_To_StringGrid(StringGrid1, 'D:\КОАСУФР\КОАСУФР10.xls') then

ShowMessage('Таблица была загруженна!');
end;
procedure TForm1.N3Click(Sender: TObject);
begin
Close;
end;
end.

Просто "Нод"ы могут быть же после данных, как с этим быть. А можно пример как вести проверку? Да и программку хотелось бы все глянуть, интересно.
volvo
Цитата
А можно пример как вести проверку? Да и программку хотелось бы все глянуть, интересно.
Ну, глянь:
procedure LockGrid(Grid: TStringGrid);
var i: Integer;
begin
for i := 0 to Pred(Grid.ColCount) do
Grid.Cols[i].BeginUpdate;
end;

procedure UnLockGrid(Grid: TStringGrid);
var i: Integer;
begin
for i := 0 to Pred(Grid.ColCount) do
Grid.Cols[i].EndUpdate;
end;

function XL_GetInfo(AGrid: TStringGrid; AXLSFile: string): boolean;
const
xlCellTypeLastCell = $0000000B;
var
XLApp, Sheet, Range: OleVariant;
Row, Rows: Integer;
curr, SpacePos: Integer;
s: string;
begin
XLApp := CreateOleObject('Excel.Application');
XLApp.Visible := False;
try
XLApp.Workbooks.Open(AXLSFile);
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];

Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
Rows := XLApp.ActiveCell.Row;
AGrid.RowCount := Rows + 1;
AGrid.FixedRows := 1;

AGrid.ColCount := 6;
AGrid.FixedCols := 1;

AGrid.Cells[2, 0] := 'B';
AGrid.Cells[3, 0] := 'D название';
AGrid.Cells[4, 0] := 'D код';
AGrid.Cells[5, 0] := 'H';

LockGrid(AGrid);

curr := Pred(AGrid.FixedRows);
for Row := 1 to Rows do
begin
Range := Sheet.Range['D' + IntToStr(Row), EmptyParam];
if not VarIsEmpty(Range) then
begin
s := Range.Value;
if (s <> '') and (Ord(s[1]) <> 160) then
begin
s := Trim(s);
//
Inc(curr);
SpacePos := LastDelimiter(Char(160), s);
AGrid.Cells[0, curr] := IntToStr(Row);
AGrid.Cells[2, curr] := Sheet.Range['B' + IntToStr(Row), EmptyParam].Value;
AGrid.Cells[3, curr] := Copy(s, 1, SpacePos - 1);
AGrid.Cells[4, curr] := Copy(s, SpacePos + 1, Length(s));
AGrid.Cells[5, curr] := Sheet.Range['H' + IntToStr(Row), EmptyParam].Value;
end;
end;
end;

UnLockGrid(AGrid);
AGrid.RowCount := curr + 1;
Result := True;
finally
if not VarIsEmpty(XLApp) then
begin
// XLApp.DisplayAlerts := False;
XLApp.Quit;
XLAPP := Unassigned;
Sheet := Unassigned;
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if XL_GetInfo(StringGrid1, 'F:\Programs\Delphi\XL\example.xls') then
begin
ShowMessage('Таблица была загружена!');
end;
end;
Тут можно еще поубирать лишние действия, вроде многократных преобразований IntToStr одного и того же числа, можно забросить обращения к Cells под один With, будет выглядеть гораздо красивее. Но код и так работает достаточно быстро за счет того, что Грид залочен, и постоянного обновления, съедающего основное время, не происходит...
Atreides
так, это понятно, а вот как мне бы отсеять из таблички данные по билетам и багажу, как выполнить проверку по значению в ячейки. и итого строки не нужны. Как вытащить данные из объединенных ячеек, типа даты? В одну табличку, все билеты, в другую багаж. И после как бы мне передавать эти данные в БД, по какому параметру? Знаю, что через SQL запросы и компоненты DataSet и SocketConnection.
volvo
Цитата
а вот как мне бы отсеять из таблички данные по билетам и багажу
Можно по-русски? Что откуда отсеять? Что получить надо и ГДЕ? Если у тебя задача что-то сделать непосредственно в XL-файле, то при чем тут вообще Дельфи? VBA тебе в помощь, и делай все, что нужно... А потом сделаешь экспорт в БД (наверняка это возможно), Дельфи вообще не нужно ни для чего, кроме как запустить VBA-код. Если же у тебя задача вытянуть из XLS определенную информацию - то что за проблема? Как обращаться к ячейке я тебе показал... Ты же знаешь, что у тебя каждая графа означает, я-то этого не знаю, названия "Дата прово" и "Ссылочный № до" мне ничего не говорят, например (а слово "багаж" я вообще только что от тебя в первый раз услышал, в присоединенном файле о нем - ни слуху ни духу)... Вот, к примеру, что должно быть в базе, если есть документ, присоединенный тобой к посту №1? По полям, желательно, напиши, что НАДО копировать, а чего - НЕ НАДО.
Цитата
и итого строки не нужны
Не нужны - убери строку №62...
Цитата
И после как бы мне передавать эти данные в БД, по какому параметру?
Опять за свое... У тебя данные пишутся в СтрингГрид, как хочешь, так и заливай их в базу, на кой черт тебе еще SocketConnection понадобился? Тут одного ДатаСета - за глаза...
Atreides
Файл эксель я не могу сам лично править, его генерирует, как отчет информационная система. В грид я решил выводить для наглядности пользователю, а так мне нужно забрать данные из столбцов и прописать в базу. Причем надо прописывать билеты и грозобагаж в отдельные базы, остальные выписки не нужны. Строки нужны только с Датой, названием и кодом станции, НОДА ( ну там 3 или 7) и дебет. Остальное нафиг не нужно, все там итого и так далее. Трабл в том, что данные не подряд идут, а с разрывами и тем более разнородные, выходит проверку делать на содержание определенного участка. Т.е. находим строки «Билеты» и отправляем в БД содержимое из блока билеты, но только дату, код и название станции, и дебет с НОД. Так же и с грузобагажом.
Atreides
А как можно получить адрес ячейки из екселя содержимое, которой удовлетворяет поисковой фразе?
Atreides
т.е. мне нужно найти и сверить сумму значений в столбце (это я выполнил) со значение в ячейки А65. Но не хотелось бы железно присваивать ячейку на случай её расширения.
unit Unit1;
var
Form1: TForm1;
// b:real;
implementation

{$R *.dfm}
procedure LockGrid(Grid: TStringGrid);
var i: Integer;
begin
for i := 0 to Pred(Grid.ColCount) do
Grid.Cols[i].BeginUpdate;
end;

procedure UnLockGrid(Grid: TStringGrid);
var i: Integer;
begin
for i := 0 to Pred(Grid.ColCount) do
Grid.Cols[i].EndUpdate;
end;

function XL_GetInfo(AGrid: TStringGrid; AXLSFile: string): boolean;
const
xlCellTypeLastCell = $0000000B;
var
XLApp, Sheet, Range: OleVariant;
Row, Rows: Integer;
curr, SpacePos: Integer;
s: string;
begin
XLApp := CreateOleObject('Excel.Application');
XLApp.Visible := False;
try
XLApp.Workbooks.Open(AXLSFile);
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];

Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
Rows := XLApp.ActiveCell.Row;
AGrid.RowCount := Rows + 1;
AGrid.FixedRows := 1;

AGrid.ColCount := 5;
AGrid.FixedCols := 0;
AGrid.Cells[1, 0] := 'Станция'; //таблица в идеале
AGrid.Cells[0, 0] := 'Код станции';
AGrid.Cells[2, 0] := 'Нод';
AGrid.Cells[3, 0] := 'Дата';
AGrid.Cells[4, 0] := 'Дебед';
//AGrid.Cells[5, 0] := 'Дебед';

LockGrid(AGrid);

curr := Pred(AGrid.FixedRows);
for Row := 1 to Rows do
begin
Range := Sheet.Range['B' + IntToStr(Row), EmptyParam];
if not VarIsEmpty(Range) then
begin
s := Range.Value;
if (s <> '') and (Ord(s[1]) <> 250) then
begin
s := Trim(s);
//
Inc(curr);
SpacePos := LastDelimiter(Char(160), s);
//AGrid.Cells[0, curr] := IntToStr(Row);
//AGrid.Cells[1, curr] := Sheet.Range['A' + IntToStr(Row), EmptyParam].Value;
//AGrid.Cells[2, curr] := Sheet.Range['B' + IntToStr(Row), EmptyParam].Value;
AGrid.Cells[0, curr] := Copy(s, 1, 6); // Вот это как то работает
AGrid.Cells[1, curr] := Copy(s, 7, Length(s));
AGrid.Cells[2, curr] := Sheet.Range['C' + IntToStr(Row), EmptyParam].Value;
AGrid.Cells[3, curr] := Sheet.Range['D' + IntToStr(Row), EmptyParam].Value;
AGrid.Cells[4, curr] := Sheet.Range['E' + IntToStr(Row), EmptyParam].Value; //порешил наконец то с ячейками
end;
end;
end;

UnLockGrid(AGrid);
AGrid.RowCount := curr + 1;
Result := True;
finally
if not VarIsEmpty(XLApp) then
begin
// XLApp.DisplayAlerts := False;
XLApp.Quit;
XLAPP := Unassigned;
Sheet := Unassigned;
end;
end;
end;


//////////////////кнопка Загрузки
procedure TForm1.Button2Click(Sender: TObject);
var
i,j,coma:integer;
deb:string;
st:string;
begin
// SocketConnection1.Connected:=true;
// SocketConnection1.AppServer.OpenBase('ora8','fs_master','fs_master');
for i := 2 to StringGrid1.RowCount - 1 do
begin
deb:=StringGrid1.Cells[4,i]; //избавляемся от минусов-тире
if (deb[1] = '-') then
deb:=copy(deb,2,length(deb)-1);

coma := pos(',',deb); // избавляемся от точки в ячейки
if coma<>0 then
deb[coma]:='.';
//end;
SocketConnection1.Connected:=true;
SocketConnection1.AppServer.openbase('ORA8','fs_master','fs'); //коннект к БД

// st:='begin delete from test where NOD=A03'+' Commit;' +' end;';;

st:='begin insert into TEST(station_code,station_name,debet,nod,data) values (' +
StringGrid1.Cells[0,i]+','+#39+StringGrid1.Cells[1,i]+#39+
',TO_NUMBER('+#39+deb+#39+'),'+#39+StringGrid1.Cells[2,i]+#39+
',to_date('+#39+StringGrid1.Cells[3,i]+#39+','+#39+'dd.MM.yyyy'+#39+'));'
+'Commit;' +'end;';

ClientDataSet1.DataRequest(st); //передаем запросик

//ClientDataSet1.Execute;

//ShowMessage('Загрузка выполнена');
end;
end;


///////////////////кнопка Выхода
procedure TForm1.Button3Click(Sender: TObject);
begin
Close; //тупо закрытие
end;

//////////////////////// не придумал название кнопки
procedure TForm1.Button4Click(Sender: TObject);
//var MyRange, V: OleVariant;
begin
// MyRange := ExcelWorksheetl.Range[‘В2', EmptyParam];
// просмотр содержимого ячейки В2
//V := MyRange.Value;
//ShowMessage(V);
// занесение в ячейку значения из окна Editl
//MyRange.Value := Editl.Text;

end;


///////////////////////////////////кнопка Выгрузки
procedure TForm1.Button1Click(Sender: TObject);
var a,b:real;
i:integer;

begin
if XL_GetInfo(StringGrid1, 'D:\КОАСУФР\ФО7ЛОКТ.xls') then //указание пути к файлику
begin
a:=0; //зануляем
b:=0; //зануляем
for i := 2 to StringGrid1.RowCount - 1 do // шагаем, дружно вниз
a:=a+StrToFloat(StringGrid1.Cells[4,i]); // продолжаем шагать по ячейкам уже
a:=a*(-1); //снова минус
Form1.Label4.caption:= FloatToStr(a); //выводим на форму
if a=b then //сравниваем
ShowMessage('Закачка данных завершена корректно');
if a<>b then
ShowMessage('Сумма итого расходиться с суммами по станциям, повторите закачку');
end;
// begin
// ShowMessage('Таблица "СводРазныхСборовПасс');
//end;
end;

end.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.