|  18.02.2009, 15:04 | #1 | 
| Участник | Query - getNo(n) - не видит данных 
			
			Пишу запрос. В нем создаю много источников. Например, поставщик, договора, проводки. Проблема в том, что он видит getNo(3) данные, а вот getNo(2), getNo(1) - не видит. Т.е. он по какой - то причине теряет данные. Не могу понять в чем дело. Ниже примерная идея кода. X++: QueryBuildDataSource qbdsTable = query.addDataSource(tableNum()); QueryBuildDataSource qbds2Trans = qbdsTable.addDataSource(tableNum()); . . . qrunVend = new QueryRun(qryVend); while (qrunVend.next()) { _VendQ = qrunVend.getno(1); vendCode = _VendQ.AccountNum; _ContrQ = qrunVend.getno(2); .. } | 
|  | 
|  18.02.2009, 15:07 | #2 | 
| Ищущий знания... | 
			
			а не проще использовать get ? наприме: _VendQ = qrunVend.get(tablennum(VendTable)); и можно посмотреть формирование самого запроса? 
				__________________ "Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем | 
|  | 
|  18.02.2009, 15:15 | #3 | 
| Боец | 
			
			ой, а что это такое ? X++: tableNum()  | 
|  | 
|  18.02.2009, 15:21 | #4 | 
| Участник | 
			
			В оригинале порядок следующий: Отбор поставщика - Отбор договора - Отбор проводок по поставщику - Отбор в ledgerTrans. На ledgerTrans ставлю суммирование. qbdsLT.orderMode(OrderMode::GROUPBY); После этого он теряет связь с DS 1, 2, 3. Как только убираю группировку, то все работает. Как же этого избежать? | 
|  | 
|  18.02.2009, 15:29 | #5 | 
| Программатор | Цитата: 
		
			Сообщение от Arahnid
			   В оригинале порядок следующий: Отбор поставщика - Отбор договора - Отбор проводок по поставщику - Отбор в ledgerTrans. На ledgerTrans ставлю суммирование. qbdsLT.orderMode(OrderMode::GROUPBY); После этого он теряет связь с DS 1, 2, 3. Как только убираю группировку, то все работает. Как же этого избежать? | 
|  | 
|  18.02.2009, 15:33 | #6 | 
| MCITP |   Цитата: 
		
			Сообщение от Arahnid
			   В оригинале порядок следующий: Отбор поставщика - Отбор договора - Отбор проводок по поставщику - Отбор в ledgerTrans. На ledgerTrans ставлю суммирование. qbdsLT.orderMode(OrderMode::GROUPBY); После этого он теряет связь с DS 1, 2, 3. Как только убираю группировку, то все работает. Как же этого избежать?  У вас будут заполнены только те поля по которым вы группируете и суммируете, всё остальное не заполнено. Так что квери то работает, просто у вас в ваших остальных таблицах все поля пустые - скорее всего вам нужно добавлять необходимые поля в группировку, либо перечитывать их внутри цикла. 
				__________________ Zhirenkov Vitaly | 
|  | 
|  18.02.2009, 17:49 | #7 | 
| Administrator | 
			
			Все гораздо проще. Есть у датасорса в квери (объект QueryBuildDataSource) свойство fetchMode. По умолчанию оно имеет значение QueryFetchMode::One2Many. Но его можно поставить в значение QueryFetchMode::One2One. Смысл следующий. Допустим у нас есть запрос из двух таблиц - шапки и строк. Если fetchMode = QueryFetchMode::One2Many, то getNo(шапки) возвратит курсор шапки только один (первый) раз для всех строк данной шапки. Т.е. это будет выглядеть так: X++: while (queryRun.next()) { = queryRun.getNo(1); do { = queryRun.getNo(2); .................... // код } while (queryRun.next()); } Т.е. при каждом вызове queryRun.next() оба курсора будут заполнены данными. Я не знаю как это связано с производительностью и зачем такая логика. Но она (логика) заложена именно такая. 
				__________________ Возможно сделать все. Вопрос времени Последний раз редактировалось sukhanchik; 18.02.2009 в 18:11. | 
|  | |
| За это сообщение автора поблагодарили: kashperuk (2), Logger (4), pbcio (0), AP-1055D (1). | |
|  18.02.2009, 18:08 | #8 | 
| Участник | 
			
			2 sukhanchik: уж больно странная у вас в коде конструкция... | 
|  | |
| За это сообщение автора поблагодарили: sukhanchik (1). | |
|  18.02.2009, 18:12 | #9 | 
| Administrator | 
			
			Спасибо, не заметил - подправил исходное сообщение
		 
				__________________ Возможно сделать все. Вопрос времени | 
|  | 
|  18.02.2009, 18:24 | #10 | 
| MCITP |   Цитата: 
		
			Сообщение от sukhanchik
			   Все гораздо проще. Есть у датасорса в квери (объект QueryBuildDataSource) свойство fetchMode. По умолчанию оно имеет значение QueryFetchMode::One2Many. Но его можно поставить в значение QueryFetchMode::One2One. Смысл следующий. Допустим у нас есть запрос из двух таблиц - шапки и строк. Если fetchMode = QueryFetchMode::One2Many, то getNo(шапки) возвратит курсор шапки только один (первый) раз для всех строк данной шапки. Т.е. это будет выглядеть так: X++: while (queryRun.next()) { = queryRun.getNo(1); do { = queryRun.getNo(2); .................... // код } while (queryRun.next()); } Т.е. при каждом вызове queryRun.next() оба курсора будут заполнены данными. Я не знаю как это связано с производительностью и зачем такая логика. Но она (логика) заложена именно такая. Я про ваше замечание про "странный эффект": X++: static void ZVVTestOne2OneMany(Args _args) { Query query = New Query(); QueryRun queryRun; QueryBuildDataSource qbds1; QueryBuildDataSource qbds2; CustTable custTable; RContractTable contractTable ; qbds1 = query.addDataSource(tableNum(CustTable)); qbds2 = qbds1.addDataSource(tableNum(RContractTable)); qbds2.relations(true); qbds2.fetchMode(QueryFetchMode::One2Many); qbds2.addRange(fieldnum(RContractTable,RContractPartnerCode)).value(queryValue("4100")); queryRun = New QueryRun(query); info(qbds1.toString()); while (queryRun.next()) { custTable = queryRun.getNo(1); contractTable = queryRun.getNo(2); info(strFmt("%1 %2", custTable.AccountNum, contractTable.RContractAccount)); } } X++: SELECT * FROM CustTable JOIN * FROM RContractTable WHERE 0 = RContractTable.RContractPartnerType AND CustTable.AccountNum = RContractTable.RContractPartnerCode AND (((RContractPartnerCode = '4100'))) 4100 0080 4100 560/1431 4100 0014 4100 0122 4100 0120 4100 0026 4100 0035 4100 0036 4100 1277/1431 4100 689/1441 UPD уточню: - QueryFetchMode::One2Many можно ставить и у первого и у обоих ДС - ничего не меняется - попробовал на 40сп2 - то же самое. Вероятно ваши данные с каких-то старых версий? Или чего в моём примере не хватает чтоб добиться вашего эффекта? 
				__________________ Zhirenkov Vitaly Последний раз редактировалось ZVV; 18.02.2009 в 18:35. | 
|  | 
|  18.02.2009, 23:35 | #11 | 
| Administrator | 
			
			2Logger: Хм... А Вы ведь правы. Я прочел только первый пост, где ни слова не упоминалось про группировку. Тогда можно считать мой пост оффтопиком в данной теме   А по поводу джобика... Хм... Действительно отрабатывает. Но ведь помню - сталкивался! Лично на грабли наступал. На Ax 4.0 SP2. Найду ведь!  Обязательно отпишу! 
				__________________ Возможно сделать все. Вопрос времени | 
|  | 
|  19.02.2009, 00:11 | #12 | 
| MCITP |   Цитата: 
		
			Сообщение от sukhanchik
			   2Logger: Хм... А Вы ведь правы. Я прочел только первый пост, где ни слова не упоминалось про группировку. Тогда можно считать мой пост оффтопиком в данной теме   А по поводу джобика... Хм... Действительно отрабатывает. Но ведь помню - сталкивался! Лично на грабли наступал. На Ax 4.0 SP2. Найду ведь!  Обязательно отпишу!   А вообще найдите, обязательно, будет интересно... У меня есть кое-какие мысли по этому поводу, возможно поможет: дело в том что в режиме QueryFetchMode::One2Many Axapta иногда имеет свойство разбивать сложный запрос на несколько запросов. Т.е. вместо одного запроса с inner join на БД отсылается несколько запросов - один запрос к "шапке", и соответсвующие запросы к "строкам", примерно как "delay" на форме. Несколько раз на такое нарывался, из-за этого были проблемы с производительностью. Установка QueryFetchMode::One2One ситуацию "вылечивало". Но я на данный момент не готов сказать в каких именно случаях такое бывает, если вспомню и\или найду - отпишусь. Так вот есть подозрение что именно в таком случае и может иметь место описанная вами выше ситуёвина, т.к. на самом деле очередной "фетч" (внутри одной "шапки") из бд вытягивает только строку из таблицы-"дитёнка" а таблица-"шапка" при этом возможно как-то чистится... Но это только мои догадки, отвечать за свои слова пока не берусь...  Модераторам - может в отдельную ветку? 
				__________________ Zhirenkov Vitaly | 
|  | 
|  19.02.2009, 09:31 | #13 | 
| Administrator | 
			
			Извините, совсем плохим стал. Прошу великодушнейшего прощения. Нашел тот запрос, в котором споткнулся в свое время с fetchMode. DAX 4.0 SP2 EE. Исходный запрос упростил для отображения работы именно fetchMode. Нюанс, с которым столкнулся вчера: сие не отрабатывает, если датасорса 2. Т.е. важно, чтобы датасорсов было больше двух. Итак: X++: static void vsuh_testFetchMode(Args _args) { CustTrans custTrans; CustTable custTable; Currency currency; Query query; QueryBuildDataSource qbds1, qbds2, qbds3; QueryRun qr; Counter cnt; ; query = new Query(); qbds1 = query.addDataSource(tablenum(CustTrans)); qbds2 = qbds1.addDataSource(tablenum(CustTable)); // qbds2.fetchMode(QueryFetchMode::One2One); qbds2.relations(true); qbds3 = qbds1.addDataSource(tablenum(Currency)); // qbds3.fetchMode(QueryFetchMode::One2One); qbds3.relations(true); qr = new QueryRun(query); while (qr.next() && cnt < 10) { custTrans = qr.getNo(1); custTable = qr.getNo(2); currency = qr.getNo(3); info(strfmt("%1-%2-%3!", custTrans.Voucher, custTable.AccountNum, currency.CurrencyCode)); cnt++; } } В таблице CustTrans ваучеры уникальные - т.е. в двух записях всегда присутствуют разные ваучеры. Итак, вариант 1 - как в джобе (fetchMode у всех QueryFetchMode::One2Many). вариант 2 - включаем fetchMode One2One у датасорса №2 вариант 3 - включаем fetchMode One2One у датасорса №3 и fetchMode One2Many у датасорса №2 вариант 4 - включаем fetchMode One2One у датасорсов №2 и №3 на датасорс №1 значение свойства fetchMode влияния не оказывает. Из примера - видно - что строки выбираются всегда - а "шапки" (в моем примере они подчинены строкам) - в зависимости от параметра fetchMode 
				__________________ Возможно сделать все. Вопрос времени Последний раз редактировалось sukhanchik; 19.02.2009 в 10:12. | 
|  | |
| За это сообщение автора поблагодарили: ZVV (3). | |
|  19.02.2009, 09:52 | #14 | 
| Участник | |
|  | 
|  19.02.2009, 10:42 | #15 | 
| MCTS | Цитата: 
		
			Допустим у нас есть запрос из двух таблиц - шапки и строк. Если fetchMode = QueryFetchMode::One2Many, то getNo(шапки) возвратит курсор шапки только один (первый) раз для всех строк данной шапки.
		
	 | 
|  | 
|  19.02.2009, 11:52 | #16 | 
| MCITP |   
			
			Да, спасибо за пример, он подтвердил высказанные мною выше подозрения: (в вашем джобе добавил X++:  info (qbds1.toString());
    info (qbds2.toString());
    info (qbds3.toString());оба One2Many: X++: SELECT * FROM CustTrans SELECT * FROM CustTable WHERE CustTrans.AccountNum = CustTable.AccountNum SELECT * FROM Currency WHERE CustTrans.CurrencyCode = Currency.CurrencyCode SQL: (CustTrans) SELECT ... FROM CUSTTRANS A WHERE (SUBSTR(NLS_LOWER(DATAAREAID),1,7)=NLS_LOWER(:in1)) ORDER BY SUBSTR(NLS_LOWER(A.DATAAREAID),1,7),SUBSTR(NLS_LOWER(A.INVOICE),1,41),SUBSTR(NLS_LOWER(A.ACCOUNTNUM),1,41) 000003_181 - - ! 000003_181 - 000001_045 - ! 000003_181 - - BYR ! CustTable One2One, Currency One2Many: X++: SELECT * FROM CustTrans JOIN * FROM CustTable WHERE CustTrans.AccountNum = CustTable.AccountNum SELECT * FROM CustTable WHERE CustTrans.AccountNum = CustTable.AccountNum SELECT * FROM Currency WHERE CustTrans.CurrencyCode = Currency.CurrencyCode SQL: (CustTrans,CustTable) SELECT ... FROM CUSTTRANS A,CUSTTABLE B WHERE (SUBSTR(NLS_LOWER(A.DATAAREAID),1,7)=NLS_LOWER(:in1)) AND ((SUBSTR(NLS_LOWER(B.DATAAREAID),1,7)=NLS_LOWER(:in2)) AND (SUBSTR(NLS_LOWER(A.ACCOUNTNUM),1,41)=SUBSTR(NLS_LOWER(B.ACCOUNTNUM),1,41))) ORDER BY SUBSTR(NLS_LOWER(A.DATAAREAID),1,7),SUBSTR(NLS_LOWER(A.ACCOUNTNUM),1,41),A.TRANSDATE,SUBSTR(NLS_LOWER(A.VOUCHER),1,41) 000003_181 - 000001_045 - ! 000003_181 - 000001_045 - BYR ! CustTable One2Many, Currency One2One: X++: SELECT * FROM CustTrans JOIN * FROM Currency WHERE CustTrans.CurrencyCode = Currency.CurrencyCode SELECT * FROM CustTable WHERE CustTrans.AccountNum = CustTable.AccountNum SELECT * FROM Currency WHERE CustTrans.CurrencyCode = Currency.CurrencyCode SQL: (CustTrans,Currency) SELECT ... FROM CUSTTRANS A,CURRENCY B WHERE (SUBSTR(NLS_LOWER(A.DATAAREAID),1,7)=NLS_LOWER(:in1)) AND ((SUBSTR(NLS_LOWER(B.DATAAREAID),1,7)=NLS_LOWER(:in2)) AND (SUBSTR(NLS_LOWER(A.CURRENCYCODE),1,7)=SUBSTR(NLS_LOWER(B.CURRENCYCODE),1,7))) ORDER BY SUBSTR(NLS_LOWER(A.DATAAREAID),1,7),SUBSTR(NLS_LOWER(A.INVOICE),1,41),SUBSTR(NLS_LOWER(A.ACCOUNTNUM),1,41)0 00003_181 - - BYR ! 000003_181 - 000001_045 - BYR ! оба One2One: X++: SELECT * FROM CustTrans JOIN * FROM CustTable WHERE CustTrans.AccountNum = CustTable.AccountNum JOIN * FROM Currency WHERE CustTrans.CurrencyCode = Currency.CurrencyCode SELECT * FROM CustTable WHERE CustTrans.AccountNum = CustTable.AccountNum SELECT * FROM Currency WHERE CustTrans.CurrencyCode = Currency.CurrencyCode SQL: (CustTrans,CustTable,Currency) SELECT ... FROM CUSTTRANS A,CUSTTABLE B,CURRENCY C WHERE (SUBSTR(NLS_LOWER(A.DATAAREAID),1,7)=NLS_LOWER(:in1)) AND ((SUBSTR(NLS_LOWER(B.DATAAREAID),1,7)=NLS_LOWER(:in2)) AND (SUBSTR(NLS_LOWER(A.ACCOUNTNUM),1,41)=SUBSTR(NLS_LOWER(B.ACCOUNTNUM),1,41))) AND ((SUBSTR(NLS_LOWER(C.DATAAREAID),1,7)=NLS_LOWER(:in3)) AND (SUBSTR(NLS_LOWER(A.CURRENCYCODE),1,7)=SUBSTR(NLS_LOWER(C.CURRENCYCODE),1,7))) ORDER BY SUBSTR(NLS_LOWER(A.DATAAREAID),1,7),SUBSTR(NLS_LOWER(A.ACCOUNTNUM),1,41),A.TRANSDATE,SUBSTR(NLS_LOWER(A.VOUCHER),1,41) 000003_181 - 000001_045 - BYR ! Насколько я понял, данный эффект происходит только в том случае, когда идёт непоследовательное соединение датасорсов! Только в этом случае Аксапта начинает "оптимизировать" (как в примере, естественно датасорсов при этом всегда больше двух, как вы верно подметили  ) и тогда нужно либо указывать fetchMode=One2One, чтоб запрос к БД был один и тогда можно пользоваться стандартным циклом по квериРун, как обычно. Либо добавлять сложные конструкции с проверкой смены "папы" последством record.Changed(). Если же порядок соединения последовательный, то  fetchMode никакого влияния не оказывает, можете сами проверить поменяв местами CustTable & CustTrans и прицепив, соответсвенно, Currency ко второму DS. Вот! Так что будьте осторожны и учитывайте данную особенность! ЗЫ Ещё из интересных особенностей данного поведения: Аксаптовский SQL-Trace не ловит подчинённые запросы к БД при такой оптимизации.  Их можно увидеть только в трэйсе на уровне БД... 
				__________________ Zhirenkov Vitaly | 
|  | |
| За это сообщение автора поблагодарили: sukhanchik (7). | |
| Теги | 
| query, queryrun, выборка, запрос (query) | 
|  | 
| 
 |