Select entre 3 tabelas

Delphi

Firebird

25/11/2014

Boa noite, estou com a seguinte estrutura no banco de dados:

CREATE TABLE AGENDA_MEDICO (
    AGM_CODIGO     INTEGER NOT NULL,
    AGM_CODIGOMED  INTEGER,
    AGM_CODIGOCLI  INTEGER,
    AGM_DIA        DATE,
    AGM_HORA       TIME
);


CREATE TABLE CLIENTES (
    CLI_CODIGO    INTEGER NOT NULL,
    CLI_NOME      VARCHAR(60),
    CLI_TELEFONE  VARCHAR(12),
    CLI_CELULAR   VARCHAR(12)
);


CREATE TABLE MEDICOS (
    MED_CODIGO  INTEGER NOT NULL,
    MED_NOME    VARCHAR(60)
);


E usando esta instrução para consulta:

SELECT 
A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,
M.MED_CODIGO, M.MED_NOME,
C.CLI_CODIGO, C.CLI_NOME

FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C
WHERE A.AGM_CODIGOMED = M.MED_CODIGO


Nas tabelas tenho 2 Medicos, 2 Clientes e 2 consultas para cada medico. Teoricamente na consulta deveria me retornar 4 registros da tabela AGENDA_MEDICO, mas está me retornando 8 registros.

Alguém poderia dar uma ajuda e uma melhorada nesta instrução?

Desde já meu muito obrigado pela atenção.
Jiraya San

Jiraya San

Curtidas 0

Melhor post

Randrade

Randrade

25/11/2014

Bom, posso estar enganado, mas você não está passando o código do cliente para verificar, assim o banco está trazendo seus dados de cada médico e cada cliente, totalizando 8.
Tente colocar a condição do cliente junto no seu select.
Testei aqui e me retornou apenas os 4 registros, não sei se era isso que vc queria.

Qualquer coisa avise.

SELECT distinct
A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,
M.MED_CODIGO, M.MED_NOME,
C.CLI_CODIGO, C.CLI_NOME
 
FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C
WHERE A.AGM_CODIGOMED = M.MED_CODIGO AND A.AGM_CODIGOCLI = C.CLI_CODIGO;
GOSTEI 1

Mais Respostas

Jiraya San

Jiraya San

25/11/2014

Opa Renilson rodei sua SQL aqui no IBExperte e me trouxe 4 registros. Amanhã vou tentar implementar ele na App.

Com relação ao código do médico para filtrar, vou estar pegando ele de um DBLouckpCombobox. Valeu, vou tentar e dou um retorno aqui.
GOSTEI 0
Randrade

Randrade

25/11/2014

Ok, caso não funcione da maneira esperada, retorne que tentarei lhe ajudar.
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Boa tarde o SQL que você me passou funcionou no IBExpert e no Componente FDQuery.
Estou tentando agora ao clicar em um dia no TMonthCalendar e tendo um médico selecionado
no DBLookupComboBox ele me filtre os dados no DBGrid.

Modelo de tela:
[img]http://arquivo.devmedia.com.br/forum/imagem/390998-20141126-164408.jpg[/img]

Para efeito de teste coloquei a mesma Instrução SQL:
with FDQryAgendaMedico do
  begin
    Close;
    SQL.Add('SELECT distinct');
    SQL.Add('A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,');
    SQL.Add('M.MED_CODIGO, M.MED_NOME,');
    SQL.Add('C.CLI_CODIGO, C.CLI_NOME');
    SQL.Add('FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C');
    SQL.Add('WHERE A.AGM_CODIGOMED = M.MED_CODIGO AND A.AGM_CODIGOCLI = C.CLI_CODIGO');
    Open;
    First;
  end;


E me apresentou o seguinte erro:
[FireDac][Phys][FB]Dynamic SQL Error
SQL error code = -104
Token unknown - line 8, column 1 SELECT.


Teria uma dica de como resolver?
Desde já obrigado pela atenção.
GOSTEI 0
Renato Rubinho

Renato Rubinho

25/11/2014

Buenas,

Deve ser só dar um "SQL.Clear" após fechar a FDQryAgendaMedico e antes de preencher o comando novamente, porque da forma que está, se a FDQryAgendaMedico possuir já algum comando ou se for aberta mais de uma vez acontecerá o erro.

with FDQryAgendaMedico do
  begin
    Close;

    SQL.Clear;        // <<<<<<<<<<<------------

    SQL.Add('SELECT distinct');
    SQL.Add('A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,');
    SQL.Add('M.MED_CODIGO, M.MED_NOME,');
    SQL.Add('C.CLI_CODIGO, C.CLI_NOME');
    SQL.Add('FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C');
    SQL.Add('WHERE A.AGM_CODIGOMED = M.MED_CODIGO AND A.AGM_CODIGOCLI = C.CLI_CODIGO');
    Open;
    First;
  end;


Abraççç,
rrubinho
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Opa bom dia a todos, rrubinho segui sua dica e funfou.

Estou tendo problemas para ao clicar em uma data no Calendário ou ao selecionar o Médico no ComboBox ele filtrar a agenda referente ao médico e dia.
SQL usada até o momento:

procedure TFrmPrincipal.SelecionaMedico;
begin
  with FDQryAgendaMedico do
  begin
    Close;
    SQL.Clear;
    SQL.Add('SELECT distinct');
    SQL.Add('A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,');
    SQL.Add('M.MED_CODIGO, M.MED_NOME,');
    SQL.Add('C.CLI_CODIGO, C.CLI_NOME, C.CLI_TELEFONE');

    SQL.Add('FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C');
    //SQL.Add('WHERE A.AGM_CODIGOMED = M.MED_CODIGO');
    SQL.Add('AND ' + FDQryAgendaMedico.ParamByName('AGM_DIA').AsString = Calendar.Date);
    SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');
    SQL.Add('ORDER BY AGM_DIA, AGM_HORA');
    Open;
    First;
  end;
end;


Só que está dando erro e não compila.
[dcc32 Error] uPrincipal.pas(300): E2010 Incompatible types: 'string' and 'TDate'
[dcc32 Warning] uPrincipal.pas(300): W1058 Implicit string cast with potential data loss from 'string' to 'ShortString'


Não estou conseguindo fazer a conversão, ou minha lógica na String SQL está incorreta.

Se puderem ajudar, desde já agradeço.
GOSTEI 0
Renato Rubinho

Renato Rubinho

25/11/2014

Buenas,

Tem uma confusãozinha no seu código... rsrs

1. Você comentou o "WHERE"

2. Neste trecho você não está filtrando nenhum campo do select
    SQL.Add('AND ' + FDQryAgendaMedico.ParamByName('AGM_DIA').AsString = Calendar.Date);

  // Se fosse uma "tradução" e tivesse selecionado o dia de hoje, seria
    ' AND '' = 28/11/2014 '


Opção 1: // Atribuindo diretamente o Valor

    SQL.Add('WHERE A.AGM_CODIGOMED = M.MED_CODIGO');

    // Atribui o valor direto do campo
    SQL.Add('AND A.AGM_DIA = '  + QuotedStr(FormatDateTime('dd.mm.yyyy',Calendar.Date)));

    SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');
    SQL.Add('ORDER BY AGM_DIA, AGM_HORA');
    Open;


Opção 2: // Passando parâmetro :

    SQL.Add('WHERE A.AGM_CODIGOMED = M.MED_CODIGO');
    // Atribui o valor de um parâmetro ao campo de data
    SQL.Add('AND A.AGM_DIA = :W_AGM_DIA');
    SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');
    SQL.Add('ORDER BY AGM_DIA, AGM_HORA');

    // Preenche o parâmetro antes do Open
    FDQryAgendaMedico.Params.ParamByName('AGM_DIA').AsDateTime = Calendar.Date;

    // Abre a query
    Open;


Abraççç,
rrubinho
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Olá galera estive até agora quebrando a cuca, mas não consegui finalizar esta questão.
Minha tabela no banco:
[img]http://arquivo.devmedia.com.br/forum/imagem/390998-20141129-221933.jpg[/img]

Meu form:
[img]http://arquivo.devmedia.com.br/forum/imagem/390998-20141126-164408.jpg[/img]

Minha função para conultar a Agenda do dia trazendo a Data, Medico e Cliente.
procedure TFrmPrincipal.SelecionaMedico;
begin
  with FDQryAgendaMedico do
  begin
    Close;
    SQL.Clear;
    SQL.Add('SELECT distinct');
    SQL.Add('A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,');
    SQL.Add('M.MED_CODIGO, M.MED_NOME,');
    SQL.Add('C.CLI_CODIGO, C.CLI_NOME, C.CLI_TELEFONE');
    SQL.Add('FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C');
    SQL.Add('WHERE A.AGM_CODIGOMED = M.MED_CODIGO');
    SQL.Add('AND A.AGM_DIA = ' + QuotedStr(FormatDateTime('dd.mm.yyyy',Calendar.Date)));
    SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');
    SQL.Add('ORDER BY AGM_DIA, AGM_HORA');
    Open;
    First;
  end;
end;


1- Rodo a aplicação e escolho um médico no ComboBox, independente de qual médico eu escolha me traz a consulta do dia. Obs. coloquei para ele começar com a data de hoje Calendar.Date:= Now;
2- Troco de Médico, continua com o mesmo resultado da consulta anterior.
3- Clico em uma data do Calendário que tem consulta gravada no banco, ele me traz o registros cadastrado, mas não troca o Médico no ComboBox.

Alguém poderia dar uma luz? se preciso for mando esta parte que estou desenvolvendo por email. Desde já obrigado pela atenção.
GOSTEI 0
Marisiana Battistella

Marisiana Battistella

25/11/2014

Bom, posso estar enganado, mas você não está passando o código do cliente para verificar, assim o banco está trazendo seus dados de cada médico e cada cliente, totalizando 8.
Tente colocar a condição do cliente junto no seu select.
Testei aqui e me retornou apenas os 4 registros, não sei se era isso que vc queria.

Qualquer coisa avise.

SELECT distinct
A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,
M.MED_CODIGO, M.MED_NOME,
C.CLI_CODIGO, C.CLI_NOME
 
FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C
WHERE A.AGM_CODIGOMED = M.MED_CODIGO AND A.AGM_CODIGOCLI = C.CLI_CODIGO;


Cada tabela que é incluida no SELECT possui uma Foreign Key que realiza o vinculo entre os dados q estão armazenados nela com os dados das demais tabelas utilizadas. Na estrutura apresentada temos 3 tabelas e as 3 contém FKs que criam esses vinculos entre os dados que elas armazenam.
Esse vinculo deve ser informado no SELECT para que o SGBD saiba localizar os dados que precisam ser retornados.
Fica muito mais fácil de estruturar uma instrução SQL corretamente quando é utilizado o padrão ANSI.
Vejam como ficaria o SELECT em questão:
SELECT A.AGM_CODIGO,
      A.AGM_CODIGOMED,
     A.AGM_CODIGOCLI,
     AGM_DIA, AGM_HORA,
     M.MED_CODIGO,
     M.MED_NOME,
    C.CLI_CODIGO,
    C.CLI_NOME
FROM AGENDA_MEDICO A
INNER JOIN MEDICOS M
ON A.AGM_CODIGOMED = M.MED_CODIGO
INNER JOIN CLIENTES C
ON A.AGM_CODIGOCLI = C.CLI_CODIGO
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Boa noite Marisiana sim cada tablela que criei tem sua Chave Primária. E também estou passando o código do cliente nesta linha:

SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');


Mesmo assim vou dar uma olhada no que me passou.
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Boa noite Marisiana sim cada tablela que criei tem sua Chave Primária. E também estou passando o código do cliente nesta linha:

SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');


Mesmo assim vou dar uma olhada no que me passou.



Se puder dar uma olhada segue link:
[url]http://www.4shared.com/folder/MhHmpU1v/_online.html[/url]
GOSTEI 0
Marisiana Battistella

Marisiana Battistella

25/11/2014

Boa noite Marisiana sim cada tablela que criei tem sua Chave Primária. E também estou passando o código do cliente nesta linha:

SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');


Mesmo assim vou dar uma olhada no que me passou.

Isso!
Eu apenas complementei o assunto do tópico e adaptei o SQL de acordo com o padrão ANSI.
Vale a pena aprender a utilizar, pois facilita a compreensão das instruções, melhora a performance, e ajuda a evitar que esqueçamos de incluir algum JOIN necessário.
GOSTEI 0
Renato Rubinho

Renato Rubinho

25/11/2014

Jiraya,

No seu código não existe nenhum filtro pelo médico.
Em que ponto você está agora ?
Está filtrando pela data corretamente, mas você quer por médico também ? Se for só isso, ao selecionar o Médico, você tem que refazer a query filtrando pelo código do médico.

// Tomando como exemplo um combo que em cada linha nos primeiros 6 dígitos são o código do médico e no restante o Nome, segue exemplo para o filtro do médico:
// Obs: No onChange do Combo você coloca a chamada do Seleciona médico para atualizar ao alterar.

procedure TFrmPrincipal.SelecionaMedico;
begin
  with FDQryAgendaMedico do
  begin
    Close;
    SQL.Clear;
    SQL.Add('SELECT distinct');
    SQL.Add('A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,');
    SQL.Add('M.MED_CODIGO, M.MED_NOME,');
    SQL.Add('C.CLI_CODIGO, C.CLI_NOME, C.CLI_TELEFONE');
    SQL.Add('FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C');
    SQL.Add('WHERE A.AGM_CODIGOMED = M.MED_CODIGO');
    SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');
    SQL.Add('AND A.AGM_DIA = ' + QuotedStr(FormatDateTime('dd.mm.yyyy',Calendar.Date)));

    if ( Trim(cbMedicos.Text) <> '' then
      SQL.Add('AND M.MED_CODIGO = ' +  Copy(cbMedicos.Text,1,6) );  <<<< Filtro pelo médico

    SQL.Add('ORDER BY AGM_DIA, AGM_HORA');
    Open;
    First;
  end;
end;


Abraççç,
Renato
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Opa boa tarde estou neste ponto, se puder dar uma olhada segue link:
http://www.4shared.com/folder/MhHmpU1v/_online.html

Coloquei os arquivos só para teste e melhor compreensão.
GOSTEI 0
Renato Rubinho

Renato Rubinho

25/11/2014

Buenas,

Foi o que falei no anterior.
Você seleciona o médico no dbcombo, mas não utiliza o código no filtro:

procedure TFrmPrincipal.SelecionaMedico;
begin
  with FDQryAgendaMedico do
  begin
    Close;
    SQL.Clear;
    SQL.Add('SELECT distinct');
    SQL.Add('A.AGM_CODIGO, A.AGM_CODIGOMED, A.AGM_CODIGOCLI, AGM_DIA, AGM_HORA,');
    SQL.Add('M.MED_CODIGO, M.MED_NOME,');
    SQL.Add('C.CLI_CODIGO, C.CLI_NOME, C.CLI_TELEFONE');
    SQL.Add('FROM AGENDA_MEDICO A, MEDICOS M, CLIENTES C');
    SQL.Add('WHERE A.AGM_CODIGOMED = M.MED_CODIGO');
    SQL.Add('AND A.AGM_CODIGOCLI = C.CLI_CODIGO');
    SQL.Add('AND A.AGM_DIA = ' + QuotedStr(FormatDateTime('dd.mm.yyyy',Calendar.Date)));
 
    if ( Trim(cbMedicos.Text) <> '' then
      SQL.Add('AND M.MED_CODIGO = ' +  IntToStr(DSMedicos.DataSet.FieldByName('MED_CODIGO').AsInteger) );  <<<< Filtro pelo médico
 
    SQL.Add('ORDER BY AGM_DIA, AGM_HORA');
    Open;
    First;
  end;
end;
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Obrigado a todos por dispor de tempo para me ajudar, obrigado mesmo.
rrubinho, testei aqui e aparentemente está funcionando corretamente. Chegando em casa vou fazer mais uns testes e depois posto aqui a solução, por enquanto muito obrigado mesmo.
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Bom dia galera, estive afastado por um tempo devido a problemas particulares. Está funcionando da foram que preciso, muito obrigado a todos pela ajuda. Não encontrei onde finalizar o Post, se alguém puder fazer isso fico grato. Valeu mesmo!
GOSTEI 0
Marisiana Battistella

Marisiana Battistella

25/11/2014

Bom dia Jiraya!
Que bom que está OK !
Se não me engano, são os moderadores e os administradores que encerram os post...
Obrigada pelo feedback!
Volte sempre!
GOSTEI 0
Jiraya San

Jiraya San

25/11/2014

Bom dia galera, estive afastado por um tempo devido a problemas particulares. Está funcionando da foram que preciso, muito obrigado a todos pela ajuda. Não encontrei onde finalizar o Post, se alguém puder fazer isso fico grato. Valeu mesmo!




RESOLVIDO
GOSTEI 0
POSTAR