-
Доброго времени суток уважаемые мастера! У меня вопрос следующего характера. Имеются две таблицы. В одной хранятся данные по регионам и по организациям, а в другой данные о хозяйственных операциях которые проводились данными организациями. Нужно сформировать вывод данных таким образом, чтобы сведения вытаскивались из этих взаимосвязаных таблиц в развернутом виде. То есть: Регион 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 - ...
-
сделай запрос, чтоб возвращал нужные регионы
-
> while not find_sql1.Eof do > for b := 1 to find_sql1.RecordCount + 1 do
Что это за безобразие ?
-
Попробовал.. Теперь у меня листинг имеет вот такой вид: Но результат от этого не поменялся 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;
-
Простите Сергей М.??? А как же тогда будет лучше? В данном случае идете перебор по записям полученным в первом запросе. То есть мы сперва вытягиваем данные по регионам, а потом под регионы начинаем тянуть уже информацию об организациях и о хозяйственных операциях произведимых данными организациями. С интересом рассмотрел бы ваш варинат...
-
А безобразие так и осталось)
-
> В данном случае идете перебор по записям полученным в первом > запросе
Если записей RecordCount, то что за запись RecordCount + 1 ?
И с чего ты взял, что св-во RecordCount будет отражать реальное число записей в НД ?
И зачем проверка на Eof, если ты все равно используешь иное граничное условие цикла - RecordCount ?
-
while not find_sql1.Eof do for b := 1 to find_sql1.RecordCount + 1 do Если в данном случае я попытаюсь сделать так "for b := 1 to find_sql1.RecordCount do", то у меня одна запись из набора пропадает
-
Не занимайся экспериментами, организовывай любой цикл по НД данных по стандартному надежному шаблону:
MyDataSet.First; //если необходимо; сразу после открытия НД вызов этого метода не требуется while not MyDataSet.Eof do begin .. работа с текущей записью .. MyDataSet.Next; end;
-
Сергей М. Я попытался убрать условие "while not find_sql1.Eof do" и оставил только "for b := 1 to find_sql1.RecordCount + 1 do".. Но дело с места и не двинулось...
-
Читай [8] до просветления.
-
Сергей М. - В том то и дело, что при извлечении из первого запроса я получаю данные по регионам. Потом я встановлюсь на первую запись и вытягиваю все сведения из таблицы хозяйственных операций. После этого я пытаюсь перейти на вторую запись из запроса find_sql1 (выбранных регионов. Но как итог у меня в StringGrid данные не появляются. Где и на каком месте происходит застревание я не знаю
-
> Сергей (05.06.08 22:18) [11]
Вот снавала приведи все свои циклы в соответствие шаблону в [8] - потом и рассуждать будем, что и где у тебя "застревает"
-
Уважаемый Сергей М.!!! Привожу результат полученного кода: 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 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; while not find_sql2.Eof do for d := 1 to find_sql2.RecordCount do begin rep_dlg.rep_tipil_tsg.Cells[1,d] := find_sql1.FieldByName('NAME').AsString; rep_dlg.rep_tipil_tsg.Cells[1,d+1] := find_sql2.FieldByName('NAME').AsString; find_sql2.Next; find_sql1.Next; end; Если конечно я вас правильно понял. Но теперь у меня все повисает на глухо.
-
> Сергей (05.06.2008 22:14:09) [9]
Ты поступил неправильно, убирать надо вторую конструкцию, а не первую. Со второй ты еще не раз наступишь на грабли.
-
> while not find_sql1.Eof do find_sql2.Close;
зависает, т.к. ты в цикле пытаешься закрыть датасет
-
> Сергей (05.06.2008 22:18:11) [11]
Твой код трудно анализировать и желание это делать, пока он в таком виде нет.
-
> Сергей (05.06.2008 22:26:13) [13]
First лишнии и опять for d := 1 to find_sql2.RecordCount
-
научись пользоваться отладчиком
-
То есть вот этой строчкой "rep_dlg.rep_tipil_tsg.Cells[1,d] := find_sql1.FieldByName('NAME').AsString"я говорю, чтобы он мне вывел первую запись из запроса find_sql1 по региону и записал в соответствующее поле в объекте StringGrid. А так как записи по хозяйственным операциям еще есть то он мне должен под записью региона вывести запси по организациям и соответственно хозяйственным операциям. Вот тут я и пишу строку "rep_dlg.rep_tipil_tsg.Cells[1,d+1] := find_sql2.FieldByName('NAME').AsString;" Ну а потом до тех пор пока не кончаться записи во втором запросе find_sql2 и после этого должна взяться следующая запись из первого запроса и перебор должен пойти дальше.. Чтобы в итоге получился желаемый вывод: Регион 1 - Организация 1 - Организация 2 - ...
-
Можно полюбопытствовать: зачем такие пляски с бубном-стрингридом, если это банально реализуется с помощью двух логически связанных датасетов, отображаемых в DBGrid'ах ?
-
Но если я уберу втору конструкцию.. А именно, если я правильно понял: 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; while not find_sql2.Eof do for d := 1 to find_sql2.RecordCount do begin rep_dlg.rep_tipil_tsg.Cells[1,d] := find_sql1.FieldByName('NAME').AsString; rep_dlg.rep_tipil_tsg.Cells[1,d+1] := find_sql2.FieldByName('NAME').AsString; find_sql2.Next; find_sql1.Next; end; То я вообще не вытяну сведения о хозяйственных операциях в какой нибудь организации...
-
MsGuns... Ну в своем случае я все это сделал. А как в итоге все это в StringGrid перетащить. В StringGridе это все потом проанализируется пользователем и потом отшлется в xls файл
-
учи кнопки F4, F7, F8
-
> Сергей (05.06.2008 22:39:21) [21]
Да никто с тобой разговаривать не будет, пока будешь писать этот ужас и игнорировать рекомендации. Тут же получается известный чукотский анекдот.
-
Увааемые мастера! Попытаюсь проанализировать свой код, чтобы было более понятно и доступно. В данном случае существует две таблицы: 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 пойти сэкономив таким образом ресурсы компьютера (памяти, процессора и т.д.).. Заранее благодарен..
-
> подскажите наиболее лучшие пути реализации данной проблемы.
тебе уже их показали и ошибки твои показали и способ проверки показали
воспользуйся хоть чем-нибудь учись слышать то, что тебе говорят, а не то, что ты хочешь услышать
-
Правильный_Вася (06.06.08 23:03) [26]
Я еще одну конструкцию придумал.. Сейчас попробую отработать а о результатах сообщу... Все равно спасибо!!!
-
> Я еще одну конструкцию придумал.
На колу мочало?
-
Уважаемые мастера!!! Огромное всем спасибо, за поддержку. Все таки нашел я выход. Если кому интересно, то код выглядит таким образом: 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; Вроде как-то так получается... Если у Вас будут идеи, то мне пожалуй было бы интересно с ними ознакомиться. Может в действительности есть более простой метод составления кода...
-
> Все таки нашел я выход. это не выход, это изврат, который и в дальшем будет тебе только мешать в работе.
> Если у Вас будут идеи, то мне пожалуй было бы интересно с ними ознакомиться. "идеи" были, высказывались , и были тобой проигнорированы, видимо не так уж тебе интересно как говоришь.
основная - научись работать с DB-Aware компонентами ... они придуманы не просто так...
-
sniknik © (08.06.08 10:05) [30] Тогда прошу прощения.. А можно увидеть ваш пример? До сего времени я слушал только обсуждения работоспособности и не работоспособности своего кода. А реального взгляда и примера я пока не увидел. Ну уж описал польностью задачу, что называется попытался разложить все по полкам, чтобы действительно было понятно. Но намека как не было так и не последовало его и до сего времени. Ладно если бы я сюда выставил свой вопрос с задачей имеющей загадочный облик и вдобавок ко всему без кода.. И с банальным требованием.. Разложите и дайте мне готовое. Но как вы заметили, я вообще то пытался что-то изобразить. Так может быть можно увидеть хоть какой нибудь намек в случае 2 конструкций for и как и каким путем это можно все обойти... Или это не реально? Я же сюда не для того чтобы початится завалился..
-
> [31] Сергей (08.06.08 22:00)
тебя в [8] пример чем не устраивает?
-
> [31] Сергей (08.06.08 22:00)
Кстати, какой великий смысл тянуть данные в стринггрид? Есть хороший компонент TDBGrid , используй его и будет тебе избавление от циклов с for/while .
-
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 тоже) там где надо..
-
> [34] Сергей (08.06.08 23:08)
> и если все верно то перевалить их все в Excel
Что это за таинственная связь между StringGrid и Excel? Из датасета нельзя что-ли их перевалить в Excel?
> Данная конструкция хороша, но только для случая если используется > 1 запрос
Бред.
-
> тебя в [8] пример чем не устраивает? мне больше нравиться совет в [20]
впрочем, можно желание из [0] реализовать, сформировать запросом требуемую структуру в одном датасете. правда для этого нужно знать структуру таблиц, и средства доступа/движок (на что из возможностей рассчитывать), а разговор здесь не о задаче > Ну уж описал польностью задачу вовсе нет, а о какойто бредовой "перекладке" данных в то что для данных не приспособлено (еще и свой пример этого бреда просят привести...)
не понятно? "набрать в бочку воды" - вот это задача, решение (одно из) - берем ведро носим воду из реки, выливаем в бочку пока не заполнится. "набрать в бочку воды решетом" - вот это уже бред... у тебя еще хуже "я ношу воду решетом, но не очень получается. покажите пример как носить так чтобы не очень много проливалось". это уже не решение задачи, это борьба с одним из тупиковых путей решения (даже если сделаешь, с данными потом нормально работать не сможешь). вот. т.что чтобы решать именно задачу надо сначала отказаться от решета в условии. и именно эти советы, по отказу, ты игнорируешь усиленней всего.
-
> А это все потом как в Excel грузить? гораздо проще из датасета чем из стринггрида. но ты судя по всему в инете не тот пример нашел...
-
-
Amoeba © (09.06.08 00:03) [38] Спасибо!!! Обязательно ознакомлюсь
-
ну раз пошла такая пьянка... пример нормального (имхо) решения (отобразить таблицы в "развернутом виде", вернее так как показано. совет в [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. и не нужно никаких циклов или извратов со стринггридом (кстати ели подумать, я ж его ни разу, сколько работаю, не использовал... вредный компонент, можно выкинуть).
-
> sniknik (09.06.2008 0:26:40) [40]
Вредно использование в качестве молотка.
-
Если автору хочется непременно показывать ДВЕ сетки: одна с организациями, а вторая с некими "операциями" (судя по всему имеются в виду "хозяйственные" операции, т.е. накладные, платежки, договора и т.д.) для КАЖДОЙ организации отдельно, то вполне достаточно два запроса - один "тянет" информацию из таблицы (справочника ?) организаций, а второй - из таблицы операций (по связке через ID организации). Оба датасета "положить" в DBGrid`ы. При этом возможно два пути реализации выборки: - Полный. В этом случае оба запроса выполняются только один раз и на клиент вытягивается ВСЯ информация. В этом случае для детального датасета (операции) нужно после каждого перемещения в основном датасете (организации) ставить соответстующий фильтр чтобы во второй сетке отображались только те операции, которые прошли по текущей организации. - Динамический. Второй запрос переоткрывается всякий раз, когда в основном изменяется текущая запись (организация) и извлекает только те записи, которые относятся к текущей организации (связка по ID) - этот способ можно реализовать через связку "Мастер-детал" чтобы не заморачиваться переоткрывать запрос "вручную". Какой именно способ выбрать - зависит от объемов данных в таблицах, мощности "клиентского" ПК и ПК сервера, пропускной способности сети и критичности к времени реакции при перемещении по сетке основного датасета на клиенте.
Перебор что первого, что второго датасета выполняется как указано в [8] с выставленным DisableControls сканируемого датасета (во избежание мерцания и вообще "тормозов")
Причем здесь стрингрид или вывод в Эксель вообще непонятно.
|