Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.06.27;
Скачать: CL | DM;

Вниз

Запрос к двум БД InterBase   Найти похожие ветки 

 
Demon   (2004-06-02 18:13) [0]

Привет Всем Знатокам!

Проблема у меня заключается в следующем:
есть 2 базы идентичные по структуре : 1 - база архив, 2 - рабочая (главная).
В конце какого-то периода данные из базы 2 переносятся в базу 1.
Теперь надо сделать так, чтоб можно было сделать запрос к двум базам.
Подскажите как можно это реализовать и возможно ли?


 
jack128 ©   (2004-06-02 18:30) [1]


> Теперь надо сделать так, чтоб можно было сделать запрос
> к двум базам.
никак. Покрайней мере не на компонентах прямого доступа. Хотя может какие нить прослойки а-ля ADO это могут...


 
sniknik ©   (2004-06-02 18:50) [2]

> Хотя может какие нить прослойки а-ля ADO это могут...
знаю единственный способ, подключится к MSSQL и уже в нем через OPENROWSET - OLE DB провайдера к IB (нужно поставить) сделать запрос, с линками к обоим базам. (не факт что получится)
аналогично можно бы и в access но там только один внешний линк к запросе позволяется... (можно подключить линкованые таблицы "стационарно" но и тут не факт что получится)

а вот BDE должен справится.

проше наверное делать всетаки в разных запросах с разными конектами  а если нужны обьедененные данные то делать это на клиенте.


 
Romkin ©   (2004-06-02 19:02) [3]

>а вот BDE должен справится.
Угу, перекачав все таблицы запроса на клиентскую часть, и только потом сделав запрос. Стоит ли?


 
Demon   (2004-06-02 19:07) [4]

> проше наверное делать всетаки в разных запросах с разными конектами  а если нужны обьедененные данные то делать это на клиенте

А неподскажеш как объеденить эти данные в один кусок?


 
jack128 ©   (2004-06-02 19:09) [5]


> А неподскажеш как объеденить эти данные в один кусок?
А что ты называешь одним куском?


 
Demon   (2004-06-02 19:15) [6]

(Набор данных 1 базы) + (Набор данных 2 базы) = кусок.
Чтоб потом по этому объединённому набору данных (т.е. кусок) сделать отчёт.


 
jack128 ©   (2004-06-02 19:32) [7]

у тебя в чем проблема то? Получить > Набор данных 1 базы или может затруднения с > Набором данных 2 базы ? ;-) Или ты без единого Dataset"a не можешь отчет построить?

Ладно пример:
положим в одной базе есть таблица customers, к которой в часности есть id города по которому проживает каждый из наших кастомеров. название города храниться в другой базе..
// sql1, sql2 - TIBSql, sql1 подключен к одной базе, sql2 - к другой
sql1.SQL.Text := "select city_id from customers where customer_name like ""Иван%""";
sql1.ExecSQl;
WhereClause := "";
while not sql1.EOF do
begin
 WhereClause := WhereClause + sql.FieldByName("city_id").AsString + ",";
 sql1.Next;
end;
sql1.Close;
if WhereClause = "" then Exit;
WhereCaluse := "where city_id in (" + copy(WhereClause, 1, Length(WhereClause) - 1) + ")";

sql2.SQL.Text := "select city_name from cities " + WhereClause;
sql2.ExecQuery;
while not sql2.EOF do
begin
 CitiesStringList.Add(sql2.FieldByName("city_name").AsString);
 sql2.Close;
end;
sql.Close;

// в результате получил список городов


 
sniknik ©   (2004-06-02 19:33) [8]

сливай все в clientdataset к примеру. с одной базы можно через провайдер данных в него закачать, с другой придется добавлять позаписьно открыв в другом датасете (может и есть способ массового дабавления не тронув имеюшиеся данные но я его не знаю, и искать влом).
а уже с clientdataset-а отчет сделать, не труднее чем сдругого датасета.


 
sniknik ©   (2004-06-02 19:36) [9]

jack128 ©   (02.06.04 19:32) [7]
обьеденение в StringList будет дольше чем рекордсет. если обьемы отчета приличные то нежелательно.


 
jack128 ©   (2004-06-02 19:46) [10]


> обьеденение в StringList будет дольше чем рекордсет
это почему?


 
sniknik ©   (2004-06-02 19:56) [11]

> это почему?
по личному опыту. ;о)) и потом если дополнять рекордсет данными второго, понадобится добавить только половину не так ли? даже не учитывая остального... быстрее.
было бы еще быстрее если найти способ массового обьеденения рекордсетов.


 
jack128 ©   (2004-06-02 20:07) [12]


> по личному опыту. ;о))
:-)


> и потом если дополнять рекордсет данными второго, понадобится
> добавить только половину не так ли?
не понял, что имеется в виду. В смысле, что если нужен union, то из часть НД из первой базы мы получаем автоматом и остается только то что нужно взять из второй базы? А чем стринг лист отличается? Кодирования разве что побольше.

>  даже не учитывая остального... быстрее.
ну если у тя получалось быстрее, то мне сложно что то возразить потому что я таких эксперементов не проводил, но по логике лист ДОЛЖЕН быть быстрее.. Уж не знаю, что Borland в мидасе замутили чтобы так получилось, что датасет оказался быстрее..


 
sniknik ©   (2004-06-02 22:11) [13]

> не понял, что имеется в виду. В смысле, что если нужен union, то из часть НД из первой базы мы получаем автоматом и остается только то что нужно взять из второй базы? А чем стринг лист отличается? Кодирования разве что побольше.
ну да union (во всяком случае так понял именно это нужно). именно
в стринг лист ты добавляеш в 2 прохода, по первому рекорсету после  по второму, а с рекордсетами в полученый первый дабавить второй, 1 проход, только по второму рекордсету, и получаем нужное в первом.

> но по логике лист ДОЛЖЕН быть быстрее..
думаеш? чтото у тебя логика хромает, рекордсеты именно для работы с данными делались причем с большими обьемами, а слинг лист... ну у него даже индексов нет, все операции перебором (наверное).
впрочем чего спорить, написать тест дело получаса, возьмешся? после сравним результат (в одного ломает).
кстати стринг лист я не тестил, так что все честно, результат заранее не знаю, могу только предположить.


 
jack128 ©   (2004-06-03 07:28) [14]

вобщем навоял я тестик..Правда с КлиентДатаСет дело имею впервые, так что проврь, пжлста ;-)
Итак есть база с табличкой в 10000 записей, я просто сделал её копию подключил к IbDatabase1 и IbDatabase2. На каждый IbDatabase есть своя транзакция IbTransaction1 и IbTransaction2. запрос прост как валенок "select NAME from ADDRESSES"

// код для ibsql + stringlist
procedure TForm1.Button1Click(Sender: TObject);
var
 sl: TStringList;
 t: Cardinal;
begin
 t := GetTickCount;
 sl := TStringList.Create;
 try
   sl.Capacity := 100;
   ibsql1.Database := IbDataBase1;
   ibsql1.Transaction := IbTransaction1;
   ibsql1.ExecQuery;
   while not ibsql1.Eof do
   begin
     sl.Add(ibsql1.FieldByName("name").AsString);
     ibsql1.next;
   end;
   ibsql1.Close;
   ibsql1.Database := IbDataBase1;
   ibsql1.Transaction := IbTransaction1;
   ibsql1.ExecQuery;
   while not ibsql1.Eof do
   begin
     sl.Add(ibsql1.FieldByName("name").AsString);
     ibsql1.next;
   end;
   ibsql1.Close;
 finally
   sl.Free;
 end;
 Caption := IntToStr(GetTickCount - t);
end;

// код для ClientDataSet
procedure TForm1.Button2Click(Sender: TObject);
var
t: Cardinal;
begin
 t := GetTickCount;
 IbDataSet1.Database := IbDataBase1;
 IbDataSet1.Transaction := IbTransaction1;
 DataSetProvider1.DataSet := IbDataSet1;
 ClientDataSet1.ProviderName := DataSetProvider1.Name;
 ClientDataSet1.Active := True;
 ClientDataSet1.Last;
 ClientDataSet1.ProviderName := "";
 IbDataSet1.Close;
 IbDataSet1.Database := IbDataBase2;
 IbDataSet1.Transaction := IbTransaction2;
 IbDataSet1.Open;
 while not IbDataSet1.eof do
 begin
   ClientDataSet1.Append;
   ClientDataSet1.FieldByName("NAME").AsString :=
     IbDataSet1.FieldByName("NAME").AsString;
   ClientDataSet1.Post;
   IbDataSet1.Next;
 end;
 IbDataSet1.Close;
 Caption := IntToStr(GetTickCount - t);
end;

результаты для листа около 2,6 сек
для клиент датасет порядка 8-9 секунд!!

причем если и первой базы данные заливатся приметно одинаково быстро (для stringlist порядка 1,2 сек, для ClientDS - 1,4 где то 10-15% отставания вполне компенсируется удобством использования), но заливка данных из второй базы, как видно все очень сильно портит. цикл while not IbDataSet1.eof do - это просто катастрофа.. Может есть какой нить способ залить данные в ClientDS? Если нет, тот все очень плохо ;-)


 
sniknik ©   (2004-06-03 08:19) [15]

вроде верно все, на работе будет время тоже проверю, динственное если у тебя ClientDataSet1 связан с какимнибудь контролом (гридом) то лутше поставить перед операциями
ClientDataSet1.DisableConstraints
и
ClientDataSet1.EnableConstraints
в конце.
преобразование имени к индексу (определение смещения) FieldByName тоже немного тормозит операцию (во втором случае 2 таких вызова).

для стринг грида тоже не помешает  
list.BeginUpdate;
list.EndUpdate
но тут по коду видно это не влияет (ты его сам создаеш и он не входит ни в какой визуальный компонент)

в общем гдето к обеду напишу результат своего теста (буду делать с dbExpress они мне кажутся попроще в использовании).


 
sniknik ©   (2004-06-03 12:05) [16]

нет приличной по обьему базы IB ;( взял привычный для себя mdb (их у меня много выляется... ;о)
но это в принципе неважно меряем то время добавления в ClientDataSet и стринг лист, а не компонент/движок.
вообще да теперь согласен, стринг лист в этом случае быстрее (даже то что с ним 2 цикла вместо одного не спасает), вот если добавлять переобразования (типы в датасетах не только строки а и float/datatime) то результаты одинаковы (приблизительно) и даже датасет выигрывает.

и у меня не получилось таких впечатляющих отличий (2,6 сек против 8-9 секунд (!!))
у меня разница составила гдето секунду, на переносе
т.е. добавление и первого и второго клиеттского рекордсета в стринг лист 2,25/2,46 сек
добовление к первому рекордсету второго 3,25/3,33сек
(мин. и макс. полученные результаты, выполнял по 6 раз всего в таблице (я чтоб не заморачиватся 2 коннекта к одной базе сделал) 13511 записей)

если брать полное время с получением данных(открытием датасетов) то оно составило гдето 10,4 и 11,4 сек

модуль как тестировал (для каждого теста перезапускать программу! иначе неправильно, 1й лабел - общее время 2 - время цикла 3 - всего строк)


unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, Grids, DBGrids, DB, Provider, DBClient, ADODB;

type
 TForm1 = class(TForm)
   ADOConnection1: TADOConnection;
   ADODataSet1: TADODataSet;
   ClientDataSet1: TClientDataSet;
   DataSetProvider1: TDataSetProvider;
   ADODataSet2: TADODataSet;
   DataSetProvider2: TDataSetProvider;
   ClientDataSet2: TClientDataSet;
   DataSource1: TDataSource;
   DBGrid1: TDBGrid;
   ListBox1: TListBox;
   Button1: TButton;
   Button2: TButton;
   Label1: TLabel;
   ADOConnection2: TADOConnection;
   Label2: TLabel;
   Label3: TLabel;
   CheckBox1: TCheckBox;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 private
 public
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
 MainSaveTime, WhileSaveTime: TDateTime;
 st: string;
 fNum1, fName1, fNum2, fName2: TField;
begin
 MainSaveTime:= Now;
 Label1.Caption:= "0:00:000";
 Label1.Caption:= "0";

 ClientDataSet1.DisableControls;
 ClientDataSet2.DisableControls;
 if CheckBox1.Checked then begin
   ClientDataSet1.PacketRecords:= 300;
   ClientDataSet2.PacketRecords:= 300;
 end;
 ListBox1.Items.BeginUpdate;

 ClientDataSet1.Open;
 ClientDataSet2.Open;
 
 ClientDataSet1.LogChanges:= false;
 ClientDataSet2.LogChanges:= false;

 fNum1:= ClientDataSet1.FieldByName("ARTICUL");
 fName1:= ClientDataSet1.FieldByName("NAME");

 fNum2:= ClientDataSet2.FieldByName("ARTICUL");
 fName2:= ClientDataSet2.FieldByName("NAME");

 WhileSaveTime:= Now;
 while not ClientDataSet2.Eof do begin
   ClientDataSet1.Append;
   fNum1.AsString:= fNum2.AsString;
   fName1.AsString:= fName2.AsString;
   ClientDataSet2.Next;
 end;
 if (ClientDataSet1.State = dsEdit) or (ClientDataSet1.State = dsInsert) then ClientDataSet1.Post;
 DateTimeToString(st, "n:ss:zzz", Now - WhileSaveTime);
 Label2.Caption:= st;

 ListBox1.Items.EndUpdate;
 ClientDataSet2.EnableControls;
 ClientDataSet1.EnableControls;

 DateTimeToString(st, "n:ss:zzz", Now - MainSaveTime);
 Label1.Caption:= st;
 Label3.Caption:= IntToStr(ClientDataSet1.RecordCount);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 MainSaveTime, WhileSaveTime: TDateTime;
 st: string;
 fNum1, fName1, fNum2, fName2: TField;
begin
 MainSaveTime:= Now;
 Label1.Caption:= "0:00:000";
 Label1.Caption:= "0";

 ClientDataSet1.DisableControls;
 ClientDataSet2.DisableControls;
 if CheckBox1.Checked then begin
   ClientDataSet1.PacketRecords:= 300;
   ClientDataSet2.PacketRecords:= 300;
 end;
 ListBox1.Items.BeginUpdate;

 ClientDataSet1.Open;
 ClientDataSet2.Open;

 ClientDataSet1.LogChanges:= false;
 ClientDataSet2.LogChanges:= false;

 fNum1:= ClientDataSet1.FieldByName("ARTICUL");
 fName1:= ClientDataSet1.FieldByName("NAME");

 fNum2:= ClientDataSet2.FieldByName("ARTICUL");
 fName2:= ClientDataSet2.FieldByName("NAME");

 WhileSaveTime:= Now;
 while not ClientDataSet1.Eof do begin
   ListBox1.Items.Add(fNum1.AsString + fName1.AsString);
   ClientDataSet1.Next;
 end;

 while not ClientDataSet2.Eof do begin
   ListBox1.Items.Add(fNum2.AsString + fName2.AsString);
   ClientDataSet2.Next;
 end;
 if (ClientDataSet1.State = dsEdit) or (ClientDataSet1.State = dsInsert) then ClientDataSet1.Post;
 DateTimeToString(st, "n:ss:zzz", Now - WhileSaveTime);
 Label2.Caption:= st;

 ListBox1.Items.EndUpdate;
 ClientDataSet2.EnableControls;
 ClientDataSet1.EnableControls;

 DateTimeToString(st, "n:ss:zzz", Now - MainSaveTime);
 Label1.Caption:= st;
 Label3.Caption:= IntToStr(ListBox1.Count);
end;

end.


 
sniknik ©   (2004-06-03 12:06) [17]

и dfm чтобы собрать програмку не напрягаясь ;о)

object Form1: TForm1
 Left = 264
 Top = 107
 Width = 691
 Height = 335
 Caption = "Form1"
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -11
 Font.Name = "MS Sans Serif"
 Font.Style = []
 OldCreateOrder = False
 PixelsPerInch = 96
 TextHeight = 13
 object Label1: TLabel
   Left = 168
   Top = 8
   Width = 32
   Height = 13
   Caption = "Label1"
 end
 object Label2: TLabel
   Left = 168
   Top = 24
   Width = 32
   Height = 13
   Caption = "Label2"
 end
 object Label3: TLabel
   Left = 168
   Top = 38
   Width = 32
   Height = 13
   Caption = "Label3"
 end
 object DBGrid1: TDBGrid
   Left = 0
   Top = 88
   Width = 369
   Height = 217
   DataSource = DataSource1
   TabOrder = 0
   TitleFont.Charset = DEFAULT_CHARSET
   TitleFont.Color = clWindowText
   TitleFont.Height = -11
   TitleFont.Name = "MS Sans Serif"
   TitleFont.Style = []
 end
 object ListBox1: TListBox
   Left = 376
   Top = 88
   Width = 297
   Height = 217
   ItemHeight = 13
   TabOrder = 1
 end
 object Button1: TButton
   Left = 288
   Top = 56
   Width = 75
   Height = 25
   Caption = "Button1"
   TabOrder = 2
   OnClick = Button1Click
 end
 object Button2: TButton
   Left = 600
   Top = 56
   Width = 75
   Height = 25
   Caption = "Button2"
   TabOrder = 3
   OnClick = Button2Click
 end
 object CheckBox1: TCheckBox
   Left = 8
   Top = 8
   Width = 137
   Height = 17
   Caption = "Use PacketRecords"
   TabOrder = 4
 end
 object ADOConnection1: TADOConnection
   ConnectionString =
     "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\DB\pos.mdb;Persi" +
     "st Security Info=False"
   LoginPrompt = False
   Provider = "Microsoft.Jet.OLEDB.4.0"
   Left = 16
   Top = 136
 end
 object ADODataSet1: TADODataSet
   Connection = ADOConnection1
   CommandText = "SELECT * FROM KKMGOODS"
   Parameters = <>
   Left = 56
   Top = 136
 end
 object ClientDataSet1: TClientDataSet
   Aggregates = <>
   DisableStringTrim = True
   Params = <>
   ProviderName = "DataSetProvider1"
   Left = 136
   Top = 136
 end
 object DataSetProvider1: TDataSetProvider
   DataSet = ADODataSet1
   Left = 96
   Top = 136
 end
 object ADODataSet2: TADODataSet
   Connection = ADOConnection2
   CommandText = "SELECT * FROM KKMGOODS"
   Parameters = <>
   Left = 56
   Top = 176
 end
 object DataSetProvider2: TDataSetProvider
   DataSet = ADODataSet2
   Left = 96
   Top = 176
 end
 object ClientDataSet2: TClientDataSet
   Aggregates = <>
   DisableStringTrim = True
   Params = <>
   ProviderName = "DataSetProvider2"
   Left = 136
   Top = 176
 end
 object DataSource1: TDataSource
   DataSet = ClientDataSet1
   Left = 184
   Top = 136
 end
 object ADOConnection2: TADOConnection
   ConnectionString =
     "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\DB\pos.mdb;Persi" +
     "st Security Info=False"
   LoginPrompt = False
   Provider = "Microsoft.Jet.OLEDB.4.0"
   Left = 16
   Top = 176
 end
end


p.s. если поставить галочку на чекбокс ситуация резко меняется, датасет становится быстрее но общее время увеличивается, нехорошо. ;о)


 
Vlad ©   (2004-06-03 12:17) [18]

http://www.ibase.ru/devinfo/ibfaq.htm#1.34
Вкратце так:
Берем БДЕ, настраиваем два алиаса, один- на одну базу, другой на другую. Затем делаем гетерогенный SQL запрос к двум базам.
Синтаксис гетерогенных запросов описан в справке по LocalSql


 
jack128 ©   (2004-06-03 12:36) [19]


> while not ClientDataSet2.Eof do begin
>    ClientDataSet1.Append;
>    fNum1.AsString:= fNum2.AsString;
>    fName1.AsString:= fName2.AsString;
>    ClientDataSet2.Next;
>  end;
>  if (ClientDataSet1.State = dsEdit) or (ClientDataSet1.State
> = dsInsert) then ClientDataSet1.Post;

А почему Post вне цикла ? ты, получается, преносишь в ClientDataSet1 только одну запись..


 
jack128 ©   (2004-06-03 12:40) [20]


> Берем БДЕ, настраиваем два алиаса, один- на одну базу, другой
> на другую. Затем делаем гетерогенный SQL запрос к двум базам.
> Синтаксис гетерогенных запросов описан в справке по LocalSql
cм [3]


 
sniknik ©   (2004-06-03 12:41) [21]

> А почему Post вне цикла ? ты, получается, преносишь в ClientDataSet1 только одну запись.
Append неявно вызывает Pos второй раз он просто лишний, а вот в конце может понадобится если конечно рекордсет был не пустои и Append хоть раз отработал.


 
jack128 ©   (2004-06-03 12:57) [22]


> Append неявно вызывает Pos
не знал, думал ексептион будет -)

знаешь, попробуй добавлять записи в лист непосредственно из ADODataSet"ов, тогда наверно разница ощутима будет..

Хотя как знать..


 
Vlad ©   (2004-06-03 13:18) [23]


> jack128 ©   (03.06.04 12:40) [20]


> cм [3]

и что смотреть ?
Автор спрашивал как сделать запрос к двум разным базам.
Можешь предложить другие варианты ?
К слову говоря, возможно выкачка всех таблиц запроса на клиента не так уж и критична для автора, мы же не знаем.


 
jack128 ©   (2004-06-03 13:34) [24]


> и что смотреть ?
на то что
а) этот способ уже был дан
б) были указаны недостатки это способа
в) после описания недостатков автор видимо счел эти недостатки сесьма серьёзными, поскольку спросил :

> > проше наверное делать всетаки в разных запросах с разными
> конектами  а если нужны обьедененные данные то делать это
> на клиенте
>
> А неподскажеш как объеденить эти данные в один кусок?
вобщем предложено два способа, любой из них в сети или/и на больших объемах будет ЯВНО быстрее BDE, а на локальном компе надо смотреть..


> sniknik ©  

Не знаю,что и думать...Разница уж очень большая в наших эксперементах..На выходных нужно базу на Access"e посмотреть, что у меня получиться.

Кстати для генерации тестовых данных для IB можно использовать IbExpert.


 
sniknik ©   (2004-06-03 14:47) [25]

> знаешь, попробуй добавлять записи в лист непосредственно из ADODataSet"ов, тогда наверно разница ощутима будет..
наверняка, основное время идет на получение через провайдер, а по другому нельзя, в условии мидас, т.е. надо полученные на клиента данные обрабатывать из клиентских датасетов (хотя почему нельзя(?)  смотря как сервер сделаеш, можно и там сливать но тогда смысл сравнений теряется ;) передавать все одно датасет придется).
поэтому и сделал дополнительно отчет времени только для перекладывания. и там по чекбоксу когда размер пакета задается начинается получение порциями (почти серверный курсор) время резко меняется на перекладывание приходится большая часть... (оно и понятно данные докачиваются в процессе)

> Не знаю,что и думать...Разница уж очень большая в наших эксперементах..
а ты как тестил, нажал одну кнопочку с базой после другую с стринг листом? тогда будет ошибочный тест.
надо при каждом тесте перезапускать программу, запустил посмотрел с базой, вышел запустил смотриш  стринг лист.
исключить возможность всяких кешей буферов и т.д.

> Кстати для генерации тестовых данных для IB можно использовать IbExpert.
не смотрел, хотя он у меня и есть. проверил простым запросом (insert into t1 select * from t1) в аксесс срабатывает, в IB нет, ну сразу и взял базу где уже есть прилично записей.


 
jack128 ©   (2004-06-03 14:53) [26]


> а ты как тестил, нажал одну кнопочку с базой после другую
> с стринг листом? тогда будет ошибочный тест.
> надо при каждом тесте перезапускать программу, запустил
> посмотрел с базой, вышел запустил смотриш  стринг лист.
> исключить возможность всяких кешей буферов и т.д.
Я даже пару раз перезагрузился -) Так что кешей никаких не было. Бред вобщем..Я твой код на выходных тоже погоняю, просто сейчас времени нема с аксесом разбираться..



Страницы: 1 вся ветка

Текущий архив: 2004.06.27;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.023 c
1-1087018221
Delphi5.01
2004-06-12 09:30
2004.06.27
Как возможно профессионально реализовать поддержку скинов програм


14-1086938919
Ditrix
2004-06-11 11:28
2004.06.27
о доброй цензуре и злой литературе...


1-1086936415
Виталя
2004-06-11 10:46
2004.06.27
Тестировка приложения


3-1085748770
Inkotex
2004-05-28 16:52
2004.06.27
А есть ли в прероде компонент чтото типа DBTreeGrid?


3-1085996825
TohaNik
2004-05-31 13:47
2004.06.27
Пользователям IB Expert.