Fórum O que há de errado no meu select com left join? #263941
03/01/2005
0
Quando executo me retorna o seguinte erro:
Ambiguous field name between table Vendas an table Clientes CODEMP
Segue meu select:
´Select Vendas.*,Clientes.NomCli FROM Vendas Left Join Clientes ON (Vendas.CodCli=Clientes.CodCli and Vendas.CodEmp=Clientes.CodEmp) WHERE CodEmp=:vCodEmp AND Pedido=:vPedido´
Vale lembrar que ambas as tabela possuem como chave primária o campo CODEMP
Um abraço
Mario[/code]
Aldus
Curtir tópico
+ 0Posts
03/01/2005
Vinicius2k
Como ambas possuem a coluna CODEMP, vc precisa determinar na condição WHERE a qual coluna pertence a tabela :
select VENDAS.*, CLIENTES.NOMCLI from VENDAS left join CLIENTES on (VENDAS.CODCLI = CLIENTES.CODCLI and VENDAS.CODEMP = CLIENTES.CODEMP) where (VENDAS.CODEMP = :vcodemp and VENDAS.PEDIDO = :vpedido)
Espero ter ajudado...
T+
Gostei + 0
03/01/2005
Aldus
Segue o código.
´Select Vendas.*,Clientes.NomCli FROM Vendas Left Join Clientes ON (Vendas.CodCli=Clientes.CodCli and Vendas.CodEmp=Clientes.CodEmp) WHERE (Vendas.CodEmp=:vCodEmp AND Vendas.Pedido=:vPedido)´
O que estaria errado?
Atenciosamente
Mario
Gostei + 0
03/01/2005
Vinicius2k
Me parece que o retorno de apenas um registro pela query está correto de acordo com a instrução SQL que vc passou...
Vc informa na condição WHERE um parametro com o número do pedido e, a não ser que vc tenha números de pedidos duplicados, somente um registro será retornado. Concorda?
T+
Gostei + 0
03/01/2005
Aldus
Veja o código:
´Select Vendas.*,Clientes.NomCli FROM Vendas Left Join Clientes ON (Vendas.CodCli=Clientes.CodCli and Vendas.CodEmp=Clientes.CodEmp) WHERE (Vendas.CodEmp=:vCodEmp)
O que eu poderia mudar?
Mario
Gostei + 0
03/01/2005
Vinicius2k
Eu não vejo motivos para que a consulta não funcione, a menos que os dados existentes na tabela não satisfaçam a condição do WHERE...
Não atender à todas as condições do WHERE é a única razão (lógica) para que a query não retorne todos os registros que vc espera que retone...
Vc já verificou a existencia dos dados dentro da tabela?
Já tentou a execução da mesma query em uma ferramenta de administração do banco de dados ao invés da aplicação?
Tente executar a query sem nenhum parametro :
select VENDAS.*, CLIENTES.NOMCLI from VENDAS left join CLIENTES on (VENDAS.CODCLI = CLIENTES.CODCLI and VENDAS.CODEMP = CLIENTES.CODEMP)
Existe também a possibilidade de que eu não esteja entendendo a lógica da sua consulta... Sua intenção é trazer todas as vendas com o respectivo nome do cliente para qual ela foi realizada? Foi desta forma que eu entendi...
Então, se só existir uma venda que satisfaça ao WHERE apenas ela será exibida...
Se a lógica não for esta, creio que vc foi pelo ´caminho errado´ e vale a pena a leitura deste tópico, para que vc entenda bem as diferenças entre os tipos de joins :
http://delphiforum.icft.com.br/forum/viewtopic.php?t=49308
T+
Gostei + 0
04/01/2005
Aldus
Quando chamo o dbgrid coloquei a seguinte sql:
Select Vendas.*,Clientes.NomCli FROM Vendas Left Join Clientes ON (Vendas.CodCli=Clientes.CodCli and Vendas.CodEmp=Clientes.CodEmp) WHERE (Vendas.CodEmp=:vCodEmp) ORDER BY Vendas.Data+Vendas.Pedido DESC
A lista veio corretamente, só que chamo novamente a lista dá o erro ´abstract error´.
Outro exemplo: chamo a lista mostra corretamente, aborto essa lista e incluo um novo pedido, ao ver a lista novamente, aparece apenas o nome do último cliente.
Tô perdido, se quiseres te envio o fonte pra você olhar.
Atenciosamente
Mario
Gostei + 0
04/01/2005
Vinicius2k
Qual o Banco de Dados ?
Se for Interbase, Firebird com IBX ou dbExpress ou MS SQL Server com ADO, eu poderei lhe ajudar, caso contrário, creio que ver o fonte não ´me diria´ nada...
Agora este ´Abstract Error´ eu nunca vi...
O que exatamente vc quer dizer com ´chamo novamente´? Lembre-se de que para passar novamente a SQL para a query, vc precisa fechá-la, passar a nova instrução, passar os parametros e reabrí-la... não seria algum procedimento faltante nesta sequência ?
T+
Gostei + 0
04/01/2005
Aldus
Uso delphi7, firebird 1.5 e dbexpress.
Utilizo assim, o usuário está no campo pedido, pressionando zero e enter mostra a lista de pedidos num dbgrid, estando na lista só é aceitável esc ou enter. Eu pressiono esc, sai do dbgrid e retorna ao campo pedido. Daí repito a operação, zero e enter para ver a lista de novo. Aqui ocorre um erro assim: ´acess violation at adress XXXX in module siga.exe. read of adress FFFFFF´.
E veja bem apenas chamei a lista sai e acessei de novo:
Segue o código de acesso a rotina de consulta, essa mesma unit uso para todas as consultas no sistemas, e apenas nessa que está usando um join aparece esse erro:
Confira por favor esse código:
Application.CreateForm(TfConsulta, fConsulta); fConsulta.vProcura := False; fConsulta.vAlias := 11; if fConsulta.ShowModal = mrOk then begin EditCodigo.Text := TransString(fConsulta.Lista.DataSource.DataSet.Fieldbyname(´Pedido´).asInteger,EditCodigo.MaxLength ); fConsulta.Release; if Length(Trim(EditCodigo.Text)) = 0 then vCodPedido:=0 else vCodPedido:=TransInteiro(EditCodigo.Text); MostraPedido(self); MostraListaItens(self); end else begin fConsulta.Release; LimpaCampos(self); MostraPedido(self); MostraListaItens(self); exit; end; end;
Criação: Application.CreateForm(TfConsulta, fConsulta);
Execução: fConsulta.ShowModal = mrOk
Destruição: fConsulta.Release;
E lá na unit fconsulta faço assim:
FormShow: fConsulta.Caption := ´Lista de Pedidos´; DM.SQL_Vendas.Close ; DM.SQL_Vendas.CommandText := ´Select Vendas.*,Clientes.NomCli FROM Vendas Left Join Clientes ON (Vendas.CodCli=Clientes.CodCli and Vendas.CodEmp=Clientes.CodEmp) WHERE (Vendas.CodEmp=:vCodEmp) ORDER BY Vendas.Data+Vendas.Pedido DESC´; //DM.SQL_Vendas.CommandText := ´Select * FROM Vendas WHERE CodEmp=:vCodEmp ORDER BY Data+Pedido DESC´; DM.SQL_Vendas.ParamByName(´vCodEmp´).AsInteger := fMenu.CodEmpSelec ; DM.SQL_Vendas.Open ; DM.CDS_Vendas.Refresh ; DM.CDS_Vendas.First ;
O código é grande mas é compreensivo.
O select no arquivo de vendas está correto assim, é a maneira correta de fazer?
Um abraço
Mario
Gostei + 0
04/01/2005
Aldus
Select * FROM Vendas WHERE CodEmp=:vCodEmp
No ClientDataSet eu já havia criado um campo lookup para trazer o nome do cliente, e com o select com join e sem mostrou da mesma forma, na primeira vez que vejo a listagem no grid aparece todos os clientes, a partir do momento que selecionei algum, quando vejo a lista de novo, só aparece o cliente do pedido selecionado anteriormente.
Deixo esse campo no clientdataset? (adicionei também todos os campos da tabela vendas), como faço, agora tô confuso.
É necessário o campo lookup ou apenas o crio no select com join, e como o acesso no dbgrid?
Tá certo a chamada do form de consulta?
1 - Application.CreateForm(TfConsulta, fConsulta);
2 - fConsulta.ShowModal
3 - fConsulta.Release;
Tô te dando um cansaço né.
Um abraço
Mario
Gostei + 0
05/01/2005
Vinicius2k
Vamos com calma... é muita informação ! :)
Bem, erros de AV não são causados por instruções SQL e sim por tentativas de acesso a objetos que não existem (nunca existiram ou já foram destruídos). Eles podem estar sendo gerados em uma das diversas funções que vc está utilizando dentro do código...
No seu código existe um END ´sobrando´ ou falta um BEGIN em alguma parte dele... melhor reavaliar... vc poderia alterá-lo desta forma, se obedecer a sua lógica :
Application.CreateForm(TfConsulta, fConsulta); fConsulta.vProcura := False; fConsulta.vAlias := 11; if fConsulta.ShowModal = mrOK then begin EditCodigo.Text := TransString(fConsulta.Lista.DataSource.DataSet.Fieldbyname(´Pedido´).asInteger, EditCodigo.MaxLength ); if Length(Trim(EditCodigo.Text)) = 0 then vCodPedido :=0 else vCodPedido := TransInteiro(EditCodigo.Text); MostraPedido(self); MostraListaItens(self); end else begin LimpaCampos(self); MostraPedido(self); MostraListaItens(self); end; fConsulta.Free;
Não use campos lookup... são péssimos para ambiente Client/Server pois são muito lentos... Joins são extremamente eficientes e substituem, com muita vantagem, os lookups. A coluna resultante de um Join será apresentado a vc como se fosse ´original´ da própria tabela principal. Vc apenas deve ter o cuidade de setar as ProviderFlags destes TFields para false, para que o Provider não tente atualizá-las em caso de ApplyUpdates.
No seu form de consulta, após abrir o DataSet, não é necessário Refresh e nem tampouco First. Ele estará sendo aberto neste exato momento, não precisando ser atualizado e o seu ponteiro do já estará posicionado no primeiro registro em buffer.
Nunca abra, ou feche diretamente Queries ligadas à ClientDataSets, elas nunca estarão abertas a menos que vc abra manualmente em algum momento... o correto é :
ClientDataSet.Close; Query.Close; // só feche se vc mesmo a tiver aberto em algum outro momento. // passe a SQL e os parametros para a query ClientDataSet.Open;
Bem, verifique estes pontos... mas quase posso garantir que seu problema é de código e não de SQL...
T+
Gostei + 0
06/01/2005
Aldus
Sempre que abro o form, abro tbm o sqldataset e o clientdataset, isso é o que faço hoje.
Quando for fazer um select, apenas fecho o client, passo o parâmetro ao sqldataset e ao abrir o client novamente, o client se encarrega de executar a nova query?
Como desabilito o providerflags do campo nomecliente que você mencionou.
Abri o dbgrid apenas com o select que você passou e funcionou bleza, só preciso desabilitar o providerflags pois não consigo gravar nada porque está tentando atualizar esse campo, que é virtual.
Obrigado pela atenção.
Mario
Gostei + 0
06/01/2005
Vinicius2k
Exatamente. Não trabalhe diretamente no SQLDataSet, a não ser com os parametros. A midas (Provider+CDS) irá se encarregar de abrir uma transação, trazer os registros para o buffer do cliente e fechar a transação.
Existem outras opções, como CommandText e Parametros no próprio ClientDataSet, mas trabalhar corretamente com estas outras opções requer um pouco de estudo da Midas. O help do Delphi é a melhor referência que conheço sobre o assunto...
De imediato vc pode adotar este procedimento:
[b:d2d07878cf]-> Abra e feche apenas o ClientDataSet e mantenha a instrução e os parametros no SQLDataSet.[/b:d2d07878cf]
Adicione todos os TFields tanto no SQLDataSet, quanto no ClientDataSet.
Cada TField terá uma propriedade ´[b:d2d07878cf]ProviderFlags[/b:d2d07878cf]´, basta passar as Flags [b:d2d07878cf]pfInUpdate[/b:d2d07878cf] e [b:d2d07878cf]pfInWhere[/b:d2d07878cf] para [b:d2d07878cf]False[/b:d2d07878cf], tanto do SQLDataSet, quanto no ClientDataSet, dos TFields vindos do JOIN, no seu caso, [b:d2d07878cf]NomCli[/b:d2d07878cf].
Blz ?
T+
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)