Многотабличный отчёт в строку
Заранее прошу прощения, если моя тема является повтором, однако поиск по форуму ответа на мой вопрос не дал. В противном случае, убедительно прошу указать аналогичную и/или смежную тему.
Описание задачи:
Необходимо выдавать на печать акт испытаний. Каждый акт имеет минимум 1 позицию.
В БД имеется 5 таблиц: 1 главная (общая информация), 4 дочерних (1 таблица = 1 тип испытаний: A,B,C,D), с общим набором ключевых полей "Номер акта"+"Номер позиции акта".
Испытания проводятся в зависимости от условий заказчика (заполнение информацией произвольное: один заказчик хочет испытания только по 1 из 4 типов, другой - 2 из 4, а третий может захотеть "по полной программе" ). Помимо этого, нормативными документами предписывается количество опытов для каждого типа испытаний, в зависимости от испытуемой детали (н-р, для болта должно проводиться 2 опыта типа С и/или 2 опыта типа D; для гайки - 1 типа А и/или 3 типа В и/или 2 типа С; для шурупа - 2 типа А).
Данные:
Чтоб было наглядней, "заполню" все 5 таблиц на основании изложенного выше.
1. Главная (AKTS: номер акта (NAkt), номер позиции (NPos), название детали (NameDet)):
Попытаемся сделать "отчёт" для акта №111...
Выборка:
Каждой таблице соответствуют свои Dataset'ы, данные в которые выбираю нехитрым способом:
Структура отчёта:
Полазив по форуму, перечитав мануалы и просмотрев ФРДемос, пришёл к выводу, что в сабрепортах моё спасение:
- на отчёт бросил Header с шапкой;
- под ним MasterData, привязанный к dataset'y главной таблицы, на котором лежит мемка с "Akts.NAkt" и 4 сабрепорта;
- на каждой странице конкретного сабрепорта лежит MasterData, привязанный на соответствующий dataset, с соответствующими мемками нужных полей.
Теперь "распечатаю" акт №111...
Что надо получить и что получается:
Пример создан в Excel'e.
Как видим, полученное отличается от желаемого. Замечу, что структуру (допустим, не в строку, а в столбик) итогового документа менять нельзя (собственно, в противном случае я б её уже давным давно поменял бы ). Только так - и никак иначе!
Нутром чую, что отсутствует связь "номер позиции"-"номер опыта", но как это сделать - ломаю голову который день. Перепробовал все возможные варианты, которые пришли в голову: и по части дизайна (=структуры) отчёта, и по части запросов. Понимаю, что ответ где-то близко, но... не совсем я, видать, понимаю принцип работы ФР'а.
Помогите, пожалуйста, и укажите мне на мои ошибки.
Всем, поучаствовавшим в решении вопроса, заранее выражаю огромнейшую благодарность!!!
Описание задачи:
Необходимо выдавать на печать акт испытаний. Каждый акт имеет минимум 1 позицию.
В БД имеется 5 таблиц: 1 главная (общая информация), 4 дочерних (1 таблица = 1 тип испытаний: A,B,C,D), с общим набором ключевых полей "Номер акта"+"Номер позиции акта".
Испытания проводятся в зависимости от условий заказчика (заполнение информацией произвольное: один заказчик хочет испытания только по 1 из 4 типов, другой - 2 из 4, а третий может захотеть "по полной программе" ). Помимо этого, нормативными документами предписывается количество опытов для каждого типа испытаний, в зависимости от испытуемой детали (н-р, для болта должно проводиться 2 опыта типа С и/или 2 опыта типа D; для гайки - 1 типа А и/или 3 типа В и/или 2 типа С; для шурупа - 2 типа А).
Данные:
Чтоб было наглядней, "заполню" все 5 таблиц на основании изложенного выше.
1. Главная (AKTS: номер акта (NAkt), номер позиции (NPos), название детали (NameDet)):
111 1 Болт
111 2 Гайка
112 1 Шуруп
2. Тип испытаний А (TypeA: номер акта (NAkt), номер позиции (NPos), номер опыта (NOpyt), результат A1 (ResA1)):
111 2 1 0.55
112 1 1 1.17
112 1 2 1.14
3. Тип испытаний B (TypeB: номер акта (NAkt), номер позиции (NPos), номер опыта (NOpyt), результат B1 (ResB1), результат B2 (ResB2)):
111 2 1 177 3.6568
111 2 2 181 3.6480
111 2 3 179 3.6592
4. Тип испытаний C (TypeC: номер акта (NAkt), номер позиции (NPos), номер опыта (NOpyt), показатель C1 (PC1), результат C1 (ResC1), показатель C2 (PC2), результат C2 (ResC2)):
111 1 1 56 3.0 116 3.2
111 1 2 55 3.6 117 3.3
111 2 1 17 3.9 320 17.5
111 2 2 18 3.9 321 17.4
5. Тип испытаний D (TypeD: номер акта (NAkt), номер позиции (NPos), номер опыта (NOpyt), результат D1 (ResD1), замечания (Zam)):
111 1 1 1251 нет
111 1 2 1509 срыв
Попытаемся сделать "отчёт" для акта №111...
Выборка:
Каждой таблице соответствуют свои Dataset'ы, данные в которые выбираю нехитрым способом:
select <список полей>
from <имя таблицы>
where <имя таблицы>.NAkt=111
Не знаю, может что-то не так делаю? Структура отчёта:
Полазив по форуму, перечитав мануалы и просмотрев ФРДемос, пришёл к выводу, что в сабрепортах моё спасение:
- на отчёт бросил Header с шапкой;
- под ним MasterData, привязанный к dataset'y главной таблицы, на котором лежит мемка с "Akts.NAkt" и 4 сабрепорта;
- на каждой странице конкретного сабрепорта лежит MasterData, привязанный на соответствующий dataset, с соответствующими мемками нужных полей.
Теперь "распечатаю" акт №111...
Что надо получить и что получается:
Пример создан в Excel'e.
Как видим, полученное отличается от желаемого. Замечу, что структуру (допустим, не в строку, а в столбик) итогового документа менять нельзя (собственно, в противном случае я б её уже давным давно поменял бы ). Только так - и никак иначе!
Нутром чую, что отсутствует связь "номер позиции"-"номер опыта", но как это сделать - ломаю голову который день. Перепробовал все возможные варианты, которые пришли в голову: и по части дизайна (=структуры) отчёта, и по части запросов. Понимаю, что ответ где-то близко, но... не совсем я, видать, понимаю принцип работы ФР'а.
Помогите, пожалуйста, и укажите мне на мои ошибки.
Всем, поучаствовавшим в решении вопроса, заранее выражаю огромнейшую благодарность!!!
Комментарии
2-й вариант - при выводе каждой строки основного набора данных переоткрывать детаил запросы с номером акта и номером позиции в качестве параметров
1й вариант, как видно из примера, не подходит. Если бы была выборка 1-к-1 - нет проблем, но тут 1-ко-многим (+4 таблицы к тому же). Разумеется, я попробую, но... буду надеяться, что ФР покажет мне совсем не то, что я вижу в IBExpert'e.
А по 2му варианту я "где-то так и думал". Но мне не понятно:
- в каком месте делать передёргивание запросов? (неужели в MasterData.OnBeforePrint?!)
- как из отчёта делать "перебор" всех IBQuery, находящихся на делфийской форме? (получается как бы "самообновление" отчёта, это разве возможно?)
По структуре отчёта замечаний нет? Всё так?
Кстати, оговорюсь, что приведённое в первом посте описание задачи, не является реальным, оно изменено и упрощено. Я оставил лишь суть. На самом деле, всё немножко сложней.
Делаю выборку вида: Структуру не менял, т.е.: В свою очередь, все сабрепорты перелинковал на "единый" набор данных.
В итоге получил "Access violation..." и самого отчёта так и не увидел.
Потом я грохнул все сабрепорты и кинул их содержимое в MasterData отчёта. Аналогично результату в IBExpert'e, выдало "чёрт знает что".
Вернул всё как было в начале. Содержимое всех сабрепортов перебросил в один. И опять "Access violation..."...
Что я не так делаю? Где подводный камень, о который я ломаю ноги?
И попутно: где можно почитать как сделать 2-й вариант: ???
Хотя бы маленький исходничек, чтоб мысль уловить, так сказать. Точнее, как сделать в Делфях я знаю, а вот как это "применить" к ФР?
DatasetName.Close;
DatasetName.ParamByName...
DatasetName.Open;
Приведу полностью запрос: Кстати, в предыдущем запросе я не понял зачем использовались SUM'ы, следовательно, на group by ругалось и не фунциклировало.
Все мемки сабрепортов кинул на МД отчёта, перелинковал, запустил.
Если смотреть на пример из первого поста, то, вместо 5 строк в отчёте (2 строки для 1-й позиции, 3 - для 2-й), я получаю 4 строки для 1-й позиции и 6 - для 2-й. Это и понятно. Получилась эдакая "лесенка": каждый первый опыт нового типа испытаний начинается не с "первой" строки, а со следующей, т.е. (для № акта 111 и позиции 1): вместо Может я не совсем ясно выразился, что мне необходимо? Что не так опять я сделал?!
По 2-му варианту сейчас буду пробовать...
Кстати, для второго варианта подразумевается использование сабрепортов или, аналогично 1-му варианту, всё в один МД отчёта?
Сделал запрос, аналогичный предложенному gpi - результат такой же, т.е. не то. Да и сведущие люди сказали (точнее, подтвердили мои предположения), что то, что я хочу, одним запросом не получить. Поэтому 1й вариант отбрасываем. Хотя, в принципе, остаются варианты вывода типа "одним запросом", н-р, через ClientDataSet, массив, даже тупо через многострочные мемки выкрутиться можно. Но... всё надо делать красиво и по уму.
По 2-му варианту...
1. Понятно, что под него остаётся первоначальная структура: на отчёте лежит MasterData, привязанный к главной таблице, в котором находится мемка с номером позиции и 4 сабрепорта.
2. В теории понятно, что при выводе номера позиции (т.е. при каждом изменении значения поля NPos) необходимо:
- закрыть все 4 датасета сабрепортов;
- передать в них новое значение номера позиции;
- открыть их.
Я попробовал в событии BeforePrint каждого сабрепорта хотя бы закрыть/открыть датасеты, но ФР говорит, что это неопределённый идентификатор...
gpi, объясни мне, пожалуйста, где, в каком событии я должен передёргивать свои параметризованные запросы? Ну не въеду я никак! (((
При первом вызове предпросмотра ругается: Если брикануть, то выпадаю в frxClass'e сюда: Если продолжить, то все последующие сообщения такие: и валятся уже сюда: Был уверен, что все эти ошибки из -за "неправильности" отчёта...
Эта темка подтолкнула на очередные ваяния. Кинул в отчёт frxIBXDatabase и 4 frxIBQuery. Всё настроил. В качестве Master'a для всех frxIBQuery указывал и frxDBDataset, завязанный на главную таблицу и расположенный на форме проекта, и внутренний frxIBQuery, завязанный аналогичным образом.
Запросы всех дочерних frxIBQuery имеют вид: В общем, всё сделал, как тут предлагалось.
В теории всё должно работать "на ура!". Однако эти, просто фашистские, виолейшены не дают жизни! Имею Delphi 2005 Pro и FastReport 3.22, но пока абсолютно не имею с ними счастья. Кто-нибудь может подскажет чего-нибудь?
Желательно сделать простой тестовый проект, демонстрирующий проблему, и выложить его здесь. После 8 Марта посмотрю. Сейчас не могу - у меня сейчас "ёлки"
С ошибками я разобрался. Проблема крылась в "переизбытке чувств" к ФРу: удалил все прошлые версии, почистил и установил 4ку. Сейчас всё в порядке. Тьфу-тьфу-тьфу, ни одной егоги!
По теме тоже всё заработало. Кинул в самом ФРе 5 IBXQuery (1 - головной, 4 - дочерних), дочерним в качестве Master'a указал головной. В результате имею то, что и хотел.
Сейчас бьюсь уже над другой "проблемой": из-за разного количества дочерних записей не так, как надо, отображаются границы мемок. Везде поставил стретчи и максхейты, а в итоге получаю нечто типа такого: вместо По-моему, из-за того, что мемки лежат в разных сабрепортах, они просто "не знают", что где-то там есть мемки бОльшей высоты. По крайней мере, это моё предположение...
Попытался "замазать" простыми линиями, но нужного не добился:
- в MasterData.OnAfterCalcHeight каждого сабрепорта вычислял высоту линии как сумму высот мемки (что-то типа счётчика; для каждого сабрепорта свой) по типу: (всё это мракобесие обнуляется в Page1OnBeforePrint)
- в MasterData.OnBeforePrint делал проверку какая высота является большей и, найдя её, присваивал эту высоту каждой линии.
В итоге получал линии большей длины (в нашем случае - высоты). Во всех остальных моих изысканиях все линии получались с высотой, равной начальной высоте мемки (т.е. высотой в 1 строку данных).
Как грамотно такое "изобразить"?
P.S: Понимаю, что мои трудности связаны с недостаточным пониманием последовательности событий, несмотря на то, что я их знаю (UserManual стр. 95). Н-р, сложилось впечатление (проверял через ShowMessage), что MasterData.OnBeforePrint на главной странице происходит и перед и после OnAfterCalcHeiht мастеров каждого сабрепорта...
Единственное, хочу добавить и уточнить для будущих "поколений" :
- мемо-"подложки" должны иметь свойства ShiftMode=smWhenOverlapped, StretchMode=smMaxHeight;
- сабрепорт должен лежать поверх мемо-"подложек";
- MasterData, на котором всё это дело лежит, должен иметь свойство Stretched=True.
Именно из-за последнего с первого раза у меня не получилось - забыл, что в ходе предыдущих экспериментов я это свойство отключил.
В любом случае, gpi, очередное тебе громадное спасибо!!!