Produto: | Datasul |
Ambiente: | Unspecified |
Versão: | 4 |
DBOs com encadeamento de EACH
DBOs com encadeamento de EACH
Sintoma:
Um comando REPOSITION QUERY falha, mesmo utilizando um rowid existente e de um registro que esteja na query. Isso geralmente resulta na mensagem 11 (Não foi possível reposicionar a query). Também as telas ficam com os botões desabilitados, já que falhando o REPOSITION não haverá registro disponível, sendo assim interpretado como query sem registros.
Causa:
Esse problema ocorre em querys que possuem mais de uma tabela. É um erro comum inverter a ordem das tabelas, fazendo com que a tabela do DBO não seja a primeira. Veja o código abaixo, supondo que o mesmo se encontra na DBO da tabela "titulo".
define query qr1 for emitente, titulo.
open query qr1 for each emitente where emitente.nome-matriz = cNomeMatriz no-lock,
each titulo where titulo.cod-emitente = emitente.cod-emitente and titulo.vl-saldo > 0 and titulo.dt-emissao >= daDataIni and titulo.dt-emissao <= daDataFim no-lock.
Como o DBO pertence a tabela "titulo", o ROWID retornado será o ROWID desta tabela. Desta forma, ao tentar efetuar um REPOSITION QUERY neste DBO, nenhum registro será encontrado, visto que o REPOSITION QUERY é sempre efetuado na primeira tabela do OPEN QUERY. No entanto, o ROWID informado neste caso pertence a segunda tabela.
Cannot reposition query to recid/rowid given.
Solução:
Para resolver esse problema, a solução é inverter a ordem das tabelas, de forma que a tabela do DBO seja a primeira no OPEN QUERY. Utilizando novamente o DBO da tabela "titulo", o exemplo anterior ficaria assim:
define query qr2 for titulo, emitente.
open query qr2 for each titulo no-lock where titulo.vl-saldo > 0 and titulo.dt-emissao >= daDataIni and titulo.dt-emissao <= daDataFim, each emitente no-lock where emitente.nome-matriz = cNomeMatriz and emitente.cod-emitente = titulo.cod-emitente.
IMPORTANTE:
Como efeito colateral dessa inversão, pode haver uma queda de performance, causada pelo aumento do número de registros lidos. Isso ocorre porque, geralmente, a segunda tabela é posta como segunda justamente porque é maior.
Usando o exemplo anterior. Supondo que a tabela emitente tenha 10 registros e para cada registro de emitente existem 100 registros de titulo. Através do WHERE apenas 2 registros de emitente deverão ser selecionados.
Usando a primeira opção (qr1), são lidos os 2 registros da tabela emitente e para cada um deles são lidos os 100 da tabela título, totalizando 202 registros (2 de emitente e 200 de titulo).
Usando a segunda opção (qr2), são lidos os 1000 registros da tabela titulo (10 * 100), e para cada um deles é lido também o respectivo registro de emitente. Como apenas 2 emitentes atendem a condição do WHERE, os mesmos 200 registros de titulo ficarão de fato disponiveis na query, ignorando os demais 800 registros de titulo que foram lidos.
Para minimizar este efeito deve-se colocar o máximo de restrições possíveis no WHERE da primeira tabela.