Здравствуйте. Необходимо вытянуть данные из MS Sql Server в Excel.
Использую набор компонентов SDac. У Query свойство FetchAll->false и FetchRows=50.
То есть засасывать по 50 записей. Это все делается для ускорения, так как 5000 записей сразу будут закачиваться долго, да и не всем они сразу нужны, и уменьшения трафика в сети.
В связи с этим, при экспорте в Excel создать вариантный массив с полученными данными не представляется возможным, так как при создании вариантного массива ему четко нужно указать размерность. Проблема в том, что у SDac'овского Query свойство TMSQuery.RecordCount меняется, как только доходим до 50-ой записи и становится 100. И так до последней.
Поэтому, делаю многомерный динамический массив и постепенно, с помощью SetLength его наращиваю.
Возникает необходимость, перед экспортом этого динамического массива перевести его в вариантный.
В Help'е к Delphi нашел процедуру DynArrayToVariant, которая и должна делать подобное.
Прототип: DynArrayToVariant(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer).
Я его вызываю так: DynArrayToVariant(ArrayA; ArrayB; TypeInfo(variant)).
Но так не работает. Выдает: 'Invalid variant type conversion'.
Как мне перевести динамический массив в вариантный используя эту процедуру или сделать это как-нибудь иначе?
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
14-02-2007 13:12
У Query свойство FetchAll->false и FetchRows=50.
Если такие ограничения у Query, то стоит ли всё загонять в динамический массив, может, лучше и в Excel перегонять по 50, 100 или 150 и т.д. строк
В трассировке DynArrayToVariant видно, что TypeInfo нужно передовать для динамического массива, а не его элементов. Все ArrayB[i] должны быть одинаковой длины. В таком варианте процедура работает.
type
TDynArrDynArrString = array of array of string;
var
ArrayB : TDynArrDynArrString;
...
// заполнение дин. массива
...
//DynArrayToVariant(ArrayA, ArrayB, TypeInfo(string));
Господа, есть какая-то залипуха, не позволяющая перевести динамический массив в вариант. Работает только тупой цикл, с поэлементным присвоением. Тем не менее, на ум пришел другой вариант: последовательно формировать в цикле вариантные массивы, длиной в то количество записей, сколько за раз засасывает SDac'овский Query и передавать серверу Excel'а. Получается, что-то типа поячеичного присвоения (помассивное). В итоге, обработчик выглядит так:
procedure TForm1.Button2Click(Sender: TObject);
var
Cell1, Cell2 , ArrayA : Variant;
nBeginCol, nBeginRow, nRow, i, j : integer;
nRowCount, nColCount : integer;
begin
MSQuery1.Close; MSQuery1.Open;
MSQuery1.First;
ExcelApp:=null; WorkBook:=null;
nBeginCol:=1; nBeginRow:=4; // Положение первой ячейки для вывода данных
nColCount:=MSQuery1.Fields.Count; // Число столбцов фиксированное
while nRowCount<MSQuery1.RecordCount do
begin
nRowCount:=MSQuery1.RecordCount+1;
ArrayA:=VarArrayCreate([1, nRowCount, 1, nColCount], varVariant);
MSQuery1.Locate('Kod_Id',MSQuery1Kod_Id.Value,[]); // Продолжаем с места, где остановились
for i:=nBeginRow-3 to nRowCount do
begin
for j:=1 to MSQuery1.Fields.Count do
ArrayA[i,j]:=Trim(MSQuery1.Fields.Fields[j-1].AsString);
MSQuery1.Next;
end;
// Считаем координаты области, куда наш массив будем кидать
Cell1 := WorkBook.WorkSheets[1].Cells[nBeginRow, nBeginCol];
Cell2 := WorkBook.WorkSheets[1].Cells[nBeginRow + nRowCount - 2, nBeginCol + nColCount-1];
Нет господа, SDac - потому, что SDac. Всю прогу переделывать на ADO не собираюсь. В перспективе 10000 записей и более. Мулька с Variant(arr) не работает. Проблема в самой конвертации из динамического массива в вариант. Вот код:
var
ArrayB : array of array of string;
...
// заполнение дин. массива
while not quTempExcel.Eof do
begin
if Length(ArrayB)<(quTempExcel.RecordCount+1) then
begin
SetLength(ArrayB, quTempExcel.RecordCount+1);
nRowCount:=quTempExcel.RecordCount+1;
end;
SetLength(ArrayB[nRow], nColCount);
for i:=0 to nColCount-1 do
ArrayB[nRow, i]:=Trim(quTempExcel.FieldByName(slFieldName[i]).AsString);
Inc(nRow);
quTempExcel.Next;
end;
...
WorkBook.WorkSheets[1].Range[Cell1, Cell2].Value:=Variant(ArrayB); //Не работает
Конец кода.
Такое тоже не работает:
DynArrayToVariant(ArrayA, ArrayB, TypeInfo(string));
WorkBook.WorkSheets[1].Range[Cell1, Cell2].Value:=ArrayA;
Пробовал делать следующее:
ArrayA := VarArrayCreate([1, nRowCount, 1, nColCount], varVariant);
for i:=1 to nRowCount-1 do
for j:=1 to nColcount do
ArrayA[i,j]:=ArrayB[i-1,j-1];
Такой перегон работает, но 10000 записей прогонять 2-ы - глупо и не рационально...
А что мешает сделать это с помощью ADO? Код достаточно прост. Около 3000 записей выводятся секунд за 10-15. И проблем особых нет. Даже не требуется установленного Excel'а.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.