![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вывод сведений из запроса в компонент StringGrid [D5, dBase, FoxPro, Paradox]
Сергей © (2008-06-05 21:10:00)Доброго времени суток уважаемые мастера! У меня вопрос следующего характера.
Имеются две таблицы. В одной хранятся данные по регионам и по организациям, а в другой данные о хозяйственных операциях которые проводились данными организациями. Нужно сформировать вывод данных таким образом, чтобы сведения вытаскивались из этих взаимосвязаных таблиц в развернутом виде. То есть:
Регион 1
- Организация 1
- Организация 2
- ...
Регион 2
- ..
При этом я использую следующий код:
with find_sql1 do
begin
find_sql1.Close;
find_sql1.SQL.Clear;
find_sql1.SQL.Add('Select * from reghoz'+
' where NOD0 = 1 and NOD1 <> 0 and NOD2 = 0'+
' ORDER BY NOD1');
find_sql1.Open;
find_sql1.First;
a := find_sql1.FieldByName('NOD1').AsInteger;
end;
while not find_sql1.Eof do
for b := 1 to find_sql1.RecordCount + 1 do
begin
rep_dlg.rep_tipil_tsg.Cells[1,b] := find_sql1.FieldByName('NAME').AsString;
find_sql2.Close;
find_sql2.SQL.Clear;
find_sql2.SQL.Add('Select * from reghoz, isp_lst'+
' where reghoz.NOD1 = '''+IntToStr(a)+''' and reghoz.NOD2 = isp_lst.id_hoz'+
' ORDER BY reghoz.NOD1, reghoz.NOD2');
find_sql2.Open;
find_sql2.First;
while not find_sql2.Eof do
for d := 1 to find_sql2.RecordCount do
begin
rep_dlg.rep_tipil_tsg.Cells[1,d+1] := find_sql2.FieldByName('NAME').AsString;
find_sql2.Next;
end;
find_sql1.Next;
Но в результате происходит вывод только сведений первого региона. Остальные регионы не вытаскиваются:
Регион 1
- Организация 1
- Организация 2
- ...
MsGuns (2008-06-09 12:34:00) [1]Если автору хочется непременно показывать ДВЕ сетки: одна с организациями, а вторая с некими "операциями" (судя по всему имеются в виду "хозяйственные" операции, т.е. накладные, платежки, договора и т.д.) для КАЖДОЙ организации отдельно, то вполне достаточно два запроса - один "тянет" информацию из таблицы (справочника ?) организаций, а второй - из таблицы операций (по связке через ID организации). Оба датасета "положить" в DBGrid`ы.
При этом возможно два пути реализации выборки:
- Полный. В этом случае оба запроса выполняются только один раз и на клиент вытягивается ВСЯ информация. В этом случае для детального датасета (операции) нужно после каждого перемещения в основном датасете (организации) ставить соответстующий фильтр чтобы во второй сетке отображались только те операции, которые прошли по текущей организации.
- Динамический. Второй запрос переоткрывается всякий раз, когда в основном изменяется текущая запись (организация) и извлекает только те записи, которые относятся к текущей организации (связка по ID) - этот способ можно реализовать через связку "Мастер-детал" чтобы не заморачиваться переоткрывать запрос "вручную".
Какой именно способ выбрать - зависит от объемов данных в таблицах, мощности "клиентского" ПК и ПК сервера, пропускной способности сети и критичности к времени реакции при перемещении по сетке основного датасета на клиенте.
Перебор что первого, что второго датасета выполняется как указано в [8] с выставленным DisableControls сканируемого датасета (во избежание мерцания и вообще "тормозов")
Причем здесь стрингрид или вывод в Эксель вообще непонятно.
Anatoly Podgoretsky (2008-06-09 11:55:00) [2]> sniknik (09.06.2008 0:26:40) [40]
Вредно использование в качестве молотка.
sniknik (2008-06-09 00:26:00) [3]ну раз пошла такая пьянка...
пример нормального (имхо) решения (отобразить таблицы в "развернутом виде", вернее так как показано. совет в [20], два связанных, мне нравиться больше).
ну, так как движок не указан то предположим что это jet, структуру таблиц тоже придумаем сами, простенькую. такую
CREATE TABLE Region (ID INT Identity(1, 1) PRIMARY KEY, Name VarChar(50))
CREATE TABLE Organiz (ID INT Identity(1, 1) PRIMARY KEY, IDReg INT, Name VarChar(50))
связь по ID - IDReg
тогда запрос вида
SELECT ID,0 AS IDReg,Name
FROM Region
UNION
SELECT r.ID,o.IDReg,' - ' & o.Name
FROM Region r
INNER JOIN Organiz o ON r.ID=o.IDReg
даст структуру (в поле Name) один в один желаемой, для отображения достаточно подключить DBGrid. и не нужно никаких циклов или извратов со стринггридом (кстати ели подумать, я ж его ни разу, сколько работаю, не использовал... вредный компонент, можно выкинуть).
Сергей (2008-06-09 00:24:00) [4]Amoeba © (09.06.08 00:03) [38]
Спасибо!!! Обязательно ознакомлюсь
Amoeba (2008-06-09 00:03:00) [5]
> А это все потом как в Excel грузить?
Автору вопроса изучать эти статьи:
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=249
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=272
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=313
sniknik (2008-06-08 23:46:00) [6]> А это все потом как в Excel грузить?
гораздо проще из датасета чем из стринггрида. но ты судя по всему в инете не тот пример нашел...
sniknik (2008-06-08 23:41:00) [7]> тебя в [8] пример чем не устраивает?
мне больше нравиться совет в [20]
впрочем, можно желание из [0] реализовать, сформировать запросом требуемую структуру в одном датасете.
правда для этого нужно знать структуру таблиц, и средства доступа/движок (на что из возможностей рассчитывать), а разговор здесь не о задаче
> Ну уж описал польностью задачу
вовсе нет, а о какойто бредовой "перекладке" данных в то что для данных не приспособлено (еще и свой пример этого бреда просят привести...)
не понятно?
"набрать в бочку воды" - вот это задача, решение (одно из) - берем ведро носим воду из реки, выливаем в бочку пока не заполнится.
"набрать в бочку воды решетом" - вот это уже бред...
у тебя еще хуже "я ношу воду решетом, но не очень получается. покажите пример как носить так чтобы не очень много проливалось".
это уже не решение задачи, это борьба с одним из тупиковых путей решения (даже если сделаешь, с данными потом нормально работать не сможешь).
вот. т.что чтобы решать именно задачу надо сначала отказаться от решета в условии. и именно эти советы, по отказу, ты игнорируешь усиленней всего.
engine (2008-06-08 23:13:00) [8]> [34] Сергей (08.06.08 23:08)
> и если все верно то перевалить их все в Excel
Что это за таинственная связь между StringGrid и Excel?
Из датасета нельзя что-ли их перевалить в Excel?
> Данная конструкция хороша, но только для случая если используется
> 1 запрос
Бред.
Сергей (2008-06-08 23:08:00) [9]engine © (08.06.08 22:54) [33] А это все потом как в Excel грузить? В моем случае я делаю форму для просмотра отчета. Чтобы пользователь мог посмотреть данные которые вытягиваются и если все верно то перевалить их все в Excel. Так вот из-за этого вариант с TDBGrid отпадает.
Про [8] пример.
MyDataSet.First; //если необходимо; сразу после открытия НД вызов этого метода не требуется
while not MyDataSet.Eof do
begin
.. работа с текущей записью ..
MyDataSet.Next;
end;
Данная конструкция хороша, но только для случая если используется 1 запрос. А в моем случае используются 2 таблицы, а потому и запросов делается два. Так как если попытаться сделать один запрос, то данные по регионам просто выпадают. А мне нужно чтобы эти наименования регионов были видны. Ну а так как при помощи двух запросов нужно делать два раза for то чтобы от этого уйти я и решил пойти по пути который назвали "извратным".
Там хоть регионы вытягиваются и встают в данном компоненте (а впрочем и в Excel тоже) там где надо..
engine (2008-06-08 22:54:00) [10]> [31] Сергей (08.06.08 22:00)
Кстати, какой великий смысл тянуть данные в стринггрид?
Есть хороший компонентTDBGrid, используй его и будет тебе избавление от циклов сfor/while.
engine (2008-06-08 22:49:00) [11]> [31] Сергей (08.06.08 22:00)
тебя в [8] пример чем не устраивает?
Сергей (2008-06-08 22:00:00) [12]sniknik © (08.06.08 10:05) [30]
Тогда прошу прощения.. А можно увидеть ваш пример? До сего времени я слушал только обсуждения работоспособности и не работоспособности своего кода. А реального взгляда и примера я пока не увидел. Ну уж описал польностью задачу, что называется попытался разложить все по полкам, чтобы действительно было понятно. Но намека как не было так и не последовало его и до сего времени.
Ладно если бы я сюда выставил свой вопрос с задачей имеющей загадочный облик и вдобавок ко всему без кода.. И с банальным требованием.. Разложите и дайте мне готовое. Но как вы заметили, я вообще то пытался что-то изобразить.
Так может быть можно увидеть хоть какой нибудь намек в случае 2 конструкций for и как и каким путем это можно все обойти... Или это не реально?
Я же сюда не для того чтобы початится завалился..
sniknik (2008-06-08 10:05:00) [13]> Все таки нашел я выход.
это не выход, это изврат, который и в дальшем будет тебе только мешать в работе.
> Если у Вас будут идеи, то мне пожалуй было бы интересно с ними ознакомиться.
"идеи" были, высказывались , и были тобой проигнорированы, видимо не так уж тебе интересно как говоришь.
основная - научись работать с DB-Aware компонентами ... они придуманы не просто так...
Сергей (2008-06-08 01:56:00) [14]Уважаемые мастера!!!
Огромное всем спасибо, за поддержку. Все таки нашел я выход. Если кому интересно, то код выглядит таким образом:
with find_sql1 do
begin
find_sql1.Close;
find_sql1.SQL.Clear;
find_sql1.SQL.Add('Select * from reghoz, isp_lst'+
' where reghoz.NOD0 = 1 and reghoz.NOD1 <> 0 and isp_lst.id_hoz = reghoz.NOD2'+
' ORDER BY reghoz.NOD1, reghoz.NOD2');
find_sql1.Open;
find_sql1.First;
a := StrToInt(find_sql1.FieldByName('NOD1').AsString);
end;
if not find_sql1.Eof then
begin
for b := 1 to find_sql1.RecordCount do
begin
with find_sql2 do
begin
find_sql2.Close;
find_sql2.SQL.Clear;
find_sql2.SQL.Add('Select * from reghoz'+
' where NOD1 = '''+(find_sql1.FieldByName('NOD1').AsString)+''' and NOD0 = 1 and NOD2 = 0');
find_sql2.Open;
reghoz_name := find_sql2.FieldByName('NAME').AsString;
end;
with find_sql3 do
begin
find_sql3.Close;
find_sql3.SQL.Clear;
find_sql3.SQL.Add('Select * from reghoz'+
' where NOD1 = '''+(find_sql1.FieldByName('NOD1').AsString)+''' and NOD0 = 1 and NOD2 <> 0');
find_sql3.Open;
c := find_sql3.RecordCount;
end;
if rep_dlg.rep_tipil_tsg.Cells[1,b] <> find_sql1.FieldByName('NOD1').AsString then
if rep_dlg.rep_tipil_tsg.Cells[1,b] = '' then
begin
rep_dlg.rep_tipil_tsg.Cells[0,b] := IntToStr(c);
rep_dlg.rep_tipil_tsg.Cells[1,b] := find_sql2.FieldByName('NOD1').AsString;
rep_dlg.rep_tipil_tsg.Cells[2,b] := reghoz_name;
rep_dlg.rep_tipil_tsg.Cells[2,b+1] := find_sql1.FieldByName('NAME').AsString;
rep_dlg.rep_tipil_tsg.Cells[1,b+1] := find_sql1.FieldByName('NOD1').AsString;
end
else
if rep_dlg.rep_tipil_tsg.Cells[1,b] <> find_sql1.FieldByName('NOD1').AsString then
if rep_dlg.rep_tipil_tsg.Cells[1,b] <> '' then
begin
rep_dlg.rep_tipil_tsg.Cells[0,b+1] := IntToStr(c);
rep_dlg.rep_tipil_tsg.Cells[1,b+1] := find_sql2.FieldByName('NOD1').AsString;
rep_dlg.rep_tipil_tsg.Cells[2,b+1] := reghoz_name;
rep_dlg.rep_tipil_tsg.Cells[2,b+2] := find_sql1.FieldByName('NAME').AsString;
rep_dlg.rep_tipil_tsg.Cells[1,b+2] := find_sql1.FieldByName('NOD1').AsString;
end;
if rep_dlg.rep_tipil_tsg.Cells[1,b] = find_sql1.FieldByName('NOD1').AsString then
begin
rep_dlg.rep_tipil_tsg.Cells[2,b+1] := find_sql1.FieldByName('NAME').AsString;
rep_dlg.rep_tipil_tsg.Cells[1,b+1] := find_sql1.FieldByName('NOD1').AsString;
end;
find_sql1.Next;
end;
end;
Вроде как-то так получается... Если у Вас будут идеи, то мне пожалуй было бы интересно с ними ознакомиться. Может в действительности есть более простой метод составления кода...
Amoeba (2008-06-06 23:35:00) [15]
> Я еще одну конструкцию придумал.
На колу мочало?
Сергей (2008-06-06 23:20:00) [16]Правильный_Вася (06.06.08 23:03) [26]
Я еще одну конструкцию придумал.. Сейчас попробую отработать а о результатах сообщу...
Все равно спасибо!!!
Правильный_Вася (2008-06-06 23:03:00) [17]
> подскажите наиболее лучшие пути реализации данной проблемы.
тебе уже их показали
и ошибки твои показали
и способ проверки показали
воспользуйся хоть чем-нибудь
учись слышать то, что тебе говорят, а не то, что ты хочешь услышать
Сергей (2008-06-06 22:02:00) [18]Увааемые мастера! Попытаюсь проанализировать свой код, чтобы было более понятно и доступно.
В данном случае существует две таблицы: reghoz и isp_lst
В таблице reghoz хранятся данные о регионах и организациях приблизительно в таком виде.
id | NOD0| NOD1| NOD2| NAME
1 | 1 | 0 | 0 | Регионы и организации
2 | 2 | 0 | 0 | Справочники
3 | 1 | 1 | 0 | Пензенская область
4 | 1 | 2 |0 | Республика мордовия
5 | 1 | 1 | 1 | ООО "Черкасское"
ну и так далее. То есть некое подобие иерархического списка регионов, организаций ну и справочника. Таким образом, для того чтобы получить список регионов Нам нужны из таблицы все те значения где где NOD0 = 1, NOD2 = 0 а NOD1 должно совпадать со значениями из таблицы по хозяйственным операциям isp_lst.
id_isp | id_reg | id_hoz | ... |
1 | 1 | 1 | ...|
Значения isp_lst.id_reg = reghoz.NOD1
isp_lst.id_hoz = reghoz.NOD2
Поэтому, для того чтобы получить заранее желаемый результат вывода в компоненте StringGrid:
Регион 1
- Организация 1
- Организация 2
- ...
Я решил воспользоваться двумя запросами. При помощи которых я в первом запросе find_sql1 извлекаю сведения по регионам и полученные значения втыкаю в компоненте StringGrid. То есть если сказать проще мне нужно чтобы вверху сперва стоял регион а под ним шел список всех организаций которые пренадлежат данному региону. и так далее по списку. Взяли регион подобрали организации.. В случае если организации для данного региона закончились взяли следующий регион и снова повторили необходимый набор действий. А для того чтобы вытащить список организаций надо обратится за данными об организациях, которые совершили хозяйственные операции. Для этого я и использовал в своем коде второй запрос find_sql2.. И как итог получился тот самый ужос, который вы все увидели.
with find_sql1 do
begin
find_sql1.Close;
find_sql1.SQL.Clear;
find_sql1.SQL.Add('Select * from reghoz'+
' where reghoz.NOD2 = 0 and reghoz.NOD0 = 1 and'+
' reghoz.NOD1 in (Select DISTINCT(id_reg) from isp_lst)'+
' ORDER BY reghoz.NOD1');
find_sql1.Open;
find_sql1.First;
a := find_sql1.FieldByName('NOD1').AsInteger;
end;
while not find_sql1.Eof do
for b := 1 to find_sql1.RecordCount + 1 do
begin
rep_dlg.rep_tipil_tsg.Cells[1,b] := find_sql1.FieldByName('NAME').AsString;
find_sql2.Close;
find_sql2.SQL.Clear;
find_sql2.SQL.Add('Select * from reghoz, isp_lst'+
' where reghoz.NOD1 = '''+IntToStr(a)+''' and isp_lst.id_hoz = reghoz.NOD2'+
' ORDER BY reghoz.NOD1, reghoz.NOD2');
find_sql2.Open;
find_sql2.First;
c := find_sql2.RecNo;
while not find_sql2.Eof do
for d := 1 to find_sql2.RecordCount do
begin
rep_dlg.rep_tipil_tsg.Cells[1,d+1] := find_sql2.FieldByName('NAME').AsString;
find_sql2.Next;
end;
find_sql1.Next;
end;
Я не исключаю вероятность того что я где-то запутался. Но я уже с этим кодом 2 недели сижу, поэтому и прошу вас указать на ошибку. И если мой подход изначально не верный, то подскажите наиболее лучшие пути реализации данной проблемы. Представление что ли сделать? Да и запихать туда данные обыкновенным insert ом, а потом order by взять и выровнять их. Или можно все таки как-то через компонент StringGrid пойти сэкономив таким образом ресурсы компьютера (памяти, процессора и т.д.)..
Заранее благодарен..
Anatoly Podgoretsky (2008-06-06 00:06:00) [19]> Сергей (05.06.2008 22:39:21) [21]
Да никто с тобой разговаривать не будет, пока будешь писать этот ужас и игнорировать рекомендации. Тут же получается известный чукотский анекдот.
Правильный_Вася (2008-06-05 22:55:00) [20]учи кнопки F4, F7, F8