08.10.2004, 14:07 | #1 |
Участник
|
проблема с query
Помогите разобраться с запросом….
Есть таблицы с такими связями: Классификатор | |-Статья затрат | | |-Объект территории | \ | Территория |-Ген. Договор \ Программа \ Направление Суть в том, что нужно сделать inner join по всем таблицам, чтобы пользователь при вызове prompt() мог ввести что угодно (range) в любой из таблиц и потом надо выбрать список значений одного из полей таблицы Классификатор. Вот текст запроса (построен по примерам с axforum, проблема – в qbDS6) Query query; QueryRun queryRun; QueryBuildDataSource qbDS1, qbDS2, qbDS3, qbDS4, qbDS5, qbDS6, qbDS7; RFORProgrammeClassifierTable rFORProgrammeClassifierTable; set dims = new set (types::string); // Declare a set of strings str dimsStr; int fldId, fldId2; ; query = new Query(); //Классификатор программ qbDS1 = query.addDataSource(tableNum(RFORProgrammeClassifierTable)); //Статья затрат qbDS2 = qbDS1.addDataSource(tableNum(RFORExpenceItemTable)); qbDS2.addLink(fieldNum(RFORProgrammeClassifierTable, RFORExpenceItem), fieldNum(RFORExpenceItemTable, RFORExpenceItem)); qbDS2.joinMode(JoinMode::EXISTSJOIN); qbDS2.fetchMode(0); //info(qbDS1.toString()); //Объект qbDS3 = qbDS1.addDataSource(tableNum(RFORTerritoryItemTable)); qbDS3.addLink(fieldNum(RFORTerritoryItemTable, RFORTerritoryItem), fieldNum(RFORProgrammeClassifierTable, RFORTerritoryItem)); qbDS3.joinMode(JoinMode::EXISTSJOIN); qbDS3.fetchMode(0); //info(qbDS1.toString()); //Территория qbDS5 = qbDS3.addDataSource(tableNum(RFORTerritoryTable)); qbDS5.addLink(fieldNum(RFORTerritoryTable, RFORTerritory), fieldNum(RFORTerritoryItemTable, RFORTerritory)); qbDS5.joinMode(JoinMode::EXISTSJOIN); qbDS5.fetchMode(0); //info(qbDS1.toString()); //Ген.договор qbDS4 = qbDS1.addDataSource(tableNum(RFORGeneralContractTable)); qbDS4.addLink(fieldNum(RFORGeneralContractTable, RFORGeneralContract), fieldNum(RFORProgrammeClassifierTable, RFORGeneralContract)); qbDS4.joinMode(JoinMode::EXISTSJOIN); qbDS4.fetchMode(0); //info(qbDS1.toString()); //Программа qbDS6 = qbDS4.addDataSource(tableNum(RFORProgrammeTable)); fldId = fieldext2id(fieldName2Id(tablenum(RFORProgrammeTable), "RFORProgramme")); fldId2 = fieldext2id(fieldName2Id(tablenum(RFORGeneralContractTable), "RFORProgramme")); qbDS6.addLink(fldId, fldId2); qbDS6.joinMode(JoinMode::EXISTSJOIN); qbDS6.fetchMode(0); info(qbDS1.toString()); связь в qbDS6 должна проходить по полям RFORProgramme но проходит по другим – запрос генерится такой: SELECT * FROM RFORProgrammeClassifierTable EXISTS JOIN * FROM RFORExpenceItemTable WHERE RFORProgrammeClassifierTable.RFORExpenceItem = RFORExpenceItemTable.RFORExpenceItem EXISTS JOIN * FROM RFORTerritoryItemTable WHERE RFORProgrammeClassifierTable.RFORTerritoryItem = RFORTerritoryItemTable.RFORTerritoryItem EXISTS JOIN * FROM RFORTerritoryTable WHERE RFORTerritoryItemTable.RFORTerritory = RFORTerritoryTable.RFORTerritory EXISTS JOIN * FROM RFORGeneralContractTable WHERE RFORProgrammeClassifierTable.RFORGeneralContract = RFORGeneralContractTable.RFORGeneralContract EXISTS JOIN * FROM RFORProgrammeTable WHERE RFORGeneralContractTable.RFORGeneralContract = RFORProgrammeTable.RFORDirection То есть поля связываются RFORGeneralContractTable.RFORGeneralContract = RFORProgrammeTable.RFORDirection А надо RFORGeneralContractTable. RFORProgramme = RFORProgrammeTable. RFORProgramme Цивилизованный путь через qbDS6.addLink(fieldNum(RFORGeneralContractTable, RFORProgamme), fieldNum(RFORProgammeTable, RFORProgamme)); приводит к тому же результату, что и через fieldName2Id(). Из-за чего может быть закавыка ? С уважением, Еремин Игорь |
|
08.10.2004, 14:38 | #2 |
----------------
|
Цитата:
public QueryBuildLink addLink(fieldId _parentField, fieldId _thisField)
Вы, вроде, хотели INNER, а пишите EXISTSJOIN. |
|
08.10.2004, 15:20 | #3 |
Участник
|
запрос писался используя материалы статьи
"Древовидная структура источников данных в Query" http://www.axforum.info/forums/showt...=7889#post7889 Суть в том, что мне не просто нужен запрос который вернет все записи, а этот query пользователи еще "ограничивают" (добавляют range) если нужно во время prompt(), и выборка данных должна содержать только тот список значений таблицы Классификатор, который не противоречит значениям, выбранным пользователями в связанных таблицах (я не знаю как какие поля и какими значениями пользователи захотят ограничить таблицы) правда, что не в ту сторону - попробовал исправить и получил также неправильный запрос: SELECT * FROM RFORProgrammeClassifierTable EXISTS JOIN * FROM RFORExpenceItemTable WHERE RFORProgrammeClassifierTable.RFORExpenceItem = RFORExpenceItemTable.RFORExpenceItem EXISTS JOIN * FROM RFORTerritoryItemTable WHERE RFORProgrammeClassifierTable.RFORTerritoryItem = RFORTerritoryItemTable.RFORTerritoryItem EXISTS JOIN * FROM RFORTerritoryTable WHERE RFORTerritoryItemTable.RFORTerritory = RFORTerritoryTable.RFORTerritory EXISTS JOIN * FROM RFORGeneralContractTable WHERE RFORProgrammeClassifierTable.RFORGeneralContract = RFORGeneralContractTable.RFORGeneralContract AND RFORProgrammeClassifierTable.SupplAgreement = RFORGeneralContractTable.RFORGeneralContract EXISTS JOIN * FROM RFORProgrammeTable Тут связь ошибочно идет еще и по полю SupplAgreement - аналитике (AND RFORProgrammeClassifierTable.SupplAgreement = RFORGeneralContractTable.RFORGeneralContract) и нет связей по полям RFORProgrammeTable (EXISTS JOIN * FROM RFORProgrammeTable) исправленный код, создающий query: Query query; QueryRun queryRun; QueryBuildDataSource qbDS1, qbDS2, qbDS3, qbDS4, qbDS5, qbDS6, qbDS7; RFORProgrammeClassifierTable rFORProgrammeClassifierTable; set dims = new set (types::string); // Declare a set of strings str dimsStr; int fldId, fldId2; ; query = new Query(); //Классификатор программ qbDS1 = query.addDataSource(tableNum(RFORProgrammeClassifierTable)); //Статья затрат qbDS2 = qbDS1.addDataSource(tableNum(RFORExpenceItemTable)); qbDS2.addLink(fieldNum(RFORProgrammeClassifierTable, RFORExpenceItem), fieldNum(RFORExpenceItemTable, RFORExpenceItem)); qbDS2.joinMode(JoinMode::EXISTSJOIN); qbDS2.fetchMode(0); //info(qbDS1.toString()); //Объект qbDS3 = qbDS1.addDataSource(tableNum(RFORTerritoryItemTable)); qbDS3.addLink(fieldNum(RFORProgrammeClassifierTable, RFORTerritoryItem), fieldNum(RFORTerritoryItemTable, RFORTerritoryItem)); qbDS3.joinMode(JoinMode::EXISTSJOIN); qbDS3.fetchMode(0); //info(qbDS1.toString()); //Территория qbDS5 = qbDS3.addDataSource(tableNum(RFORTerritoryTable)); qbDS5.addLink(fieldNum(RFORTerritoryItemTable, RFORTerritory), fieldNum(RFORTerritoryTable, RFORTerritory)); qbDS5.joinMode(JoinMode::EXISTSJOIN); qbDS5.fetchMode(0); //info(qbDS1.toString()); //Ген.договор qbDS4 = qbDS1.addDataSource(tableNum(RFORGeneralContractTable)); qbDS4.addLink(fieldNum(RFORProgrammeClassifierTable, RFORGeneralContract), fieldNum(RFORGeneralContractTable, RFORGeneralContract)); qbDS4.joinMode(JoinMode::EXISTSJOIN); qbDS4.fetchMode(0); //info(qbDS1.toString()); //Программа qbDS6 = qbDS4.addDataSource(tableNum(RFORProgrammeTable)); qbDS4.addLink(fieldNum(RFORGeneralContractTable, RFORProgramme), fieldNum(RFORProgrammeTable, RFORProgramme)); qbDS6.joinMode(JoinMode::EXISTSJOIN); qbDS6.fetchMode(0); info(qbDS1.toString()); |
|
08.10.2004, 15:37 | #4 |
Участник
|
Re: проблема с query
Цитата:
Изначально опубликовано EreminIgor
Вот текст запроса (построен по примерам с axforum, проблема – в qbDS6) Создайте нужный вам Query в AOT. Там его создавать намного легче. В коде напишите ОДНУ строчку PHP код:
Мучайте его также, как и созданный в коде. Но! Созданный в АОТ query, у вас будет гарантированно правильным. Да и проверять его намного легче. |
|
|
За это сообщение автора поблагодарили: d_alexe (1). |
08.10.2004, 16:10 | #5 |
Участник
|
собственно, я с этого и начинал...
еще раз проверил - создал query аналогичный своему программному ошибки логические остаются - query работает неправильно: то есть если пользователь выбирает направление или программу (то есть самые дальные таблицы в иерархии), и заводит по ней range, то запрос работает неправильно - выдаются все доступные строки таблицы "Классификатор" в трассировке запрос роазбирается на два запроса: первый с таблицами Классификатор, Объект, Территория и Статья затрат. Второй с таблицами направление и программа. Соответственно если фильтр пользователя приходится на программу то первый запрос select * from RFORProgrammeClassifierTable .... уже выдает все значения строк таблицы классификатор и программой они не ограничиваются ! |
|
08.10.2004, 16:36 | #6 |
----------------
|
Некоторые общие рекомендации, которые я стараюсь выполнять при работе с Query
1. Минимизировать количество ветвлений 2. Использовать только inner join 3. Не объединять более 5 таблиц Что делать в вашем случаи не знаю. Можно после диалога с юзером разбивать запрос на 2 (главный, по которому строится отчет и ограничитель, который выполняется в цикле), но это МНОГО кодинга. Наверное, имеет смысл пойти на упрощение задачи. |
|
08.10.2004, 17:49 | #7 |
NavAx
|
2 EreminIgor: вряд ли кто тебе ответит на этот вопрос. Хотя бы потому, что в такой куче кода, возиться не охота. Чудес явно нет, если аккуратно перебрать работать будет. Для начала, заставь работать запрос в аксаптовском sql, чтоб знать, что логика правильная. А потом, по частям, делай Query и на каждом шагу проверяй. Тогда багу не укрыться!
P.S. Осознать такой запрос целиком не возможно физиологически даже в момент озарения, т.к. 7 сущностей, и еще связи...
__________________
Isn't it nice when things just work? |
|
11.10.2004, 16:57 | #8 |
Участник
|
Решил-таки...всем кто участвовал в обсуждении большое спасибо за ответы
Упростил задачу - немного денормализовал таблицу "Генеральный договор" - храню там еще и поле "Направление", таким образом 2 join с таблицами "программа" и "направление" стали ненужными. Запрос правильно заработал (программно), только когда стал выглядель так: Классификатор | |-Статья затрат | |-Ген. Договор (включая поля Программа, Направление) | |-Объект территории \ Территория (то есть подчиненная относительно таблицы "Классификатор" таблица, имеющая в свою очередь подчиненную таблицу, находится в "конце" запроса) Видимо, запрос с двумя "ветвями" подчинения выполняется некорректно всегда. Привожу исходный код: static void TestQuery(Args _args) { Query query; QueryRun queryRun; QueryBuildDataSource qbDS1, qbDS2, qbDS3, qbDS4, qbDS5; RFORProgrammeClassifierTable rFORProgrammeClassifierTable; set dims = new set (types::string); // Declare a set of strings str dimsStr; int fldId, fldId2; ; query = new Query(); //Классификатор программ qbDS1 = query.addDataSource(tableNum(RFORProgrammeClassifierTable)); qbDS1.addRange(fieldNum(RFORProgrammeClassifierTable, RFORProgrammeClassifier)); //Ген.договор (в т.ч. программа и направление) qbDS4 = qbDS1.addDataSource(tableNum(RFORGeneralContractTable)); qbDS4.addLink(fieldNum(RFORProgrammeClassifierTable, RFORGeneralContract), fieldNum(RFORGeneralContractTable, RFORGeneralContract)); qbDS4.joinMode(JoinMode::EXISTSJOIN); qbDS4.fetchMode(0); qbDS4.addRange(fieldNum(RFORGeneralContractTable, RFORProgramme)); qbDS4.addRange(fieldNum(RFORGeneralContractTable, RFORDirection)); qbDS4.addRange(fieldNum(RFORGeneralContractTable, RFORGeneralContract)); //info(qbDS1.toString()); //Статья затрат qbDS2 = qbDS1.addDataSource(tableNum(RFORExpenceItemTable)); qbDS2.addLink(fieldNum(RFORExpenceItemTable, RFORExpenceItem), fieldNum(RFORProgrammeClassifierTable, RFORExpenceItem)); qbDS2.joinMode(JoinMode::EXISTSJOIN); qbDS2.fetchMode(0); qbDS2.addRange(fieldNum(RFORExpenceItemTable, RFORExpenceItem)); //info(qbDS1.toString()); //Объект qbDS3 = qbDS1.addDataSource(tableNum(RFORTerritoryItemTable)); qbDS3.addLink(fieldNum(RFORTerritoryItemTable, RFORTerritoryItem), fieldNum(RFORProgrammeClassifierTable, RFORTerritoryItem)); qbDS3.joinMode(JoinMode::EXISTSJOIN); qbDS3.fetchMode(0); qbDS3.addRange(fieldNum(RFORTerritoryItemTable, RFORTerritoryItem)); //info(qbDS1.toString()); //Территория qbDS5 = qbDS3.addDataSource(tableNum(RFORTerritoryTable)); qbDS5.addLink(fieldNum(RFORTerritoryItemTable, RFORTerritory), fieldNum(RFORTerritoryTable, RFORTerritory)); qbDS5.joinMode(JoinMode::EXISTSJOIN); qbDS5.fetchMode(0); qbDS5.addRange(fieldNum(RFORTerritoryTable, RFORTerritory)); //info(qbDS1.toString()); queryRun = new QueryRun(query); if (queryRun.prompt()) { while (queryRun.next()) { rFORProgrammeClassifierTable = queryRun.get(tablenum(RFORProgrammeClassifierTable)); dims.add(rFORProgrammeClassifierTable.SupplAgreement[3]); } } box::info(dims.toString()); } |
|