Retornar registros q possuam referencia em uma tabela ou não

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
Responder
Tinho
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 317
Registrado em: Seg, 16 Nov 2009 4:50 pm
Localização: São Paulo - SP

Gente tenho um caso que não sei como resolver ou pelo menos não enxerguei a solução ainda, por isso gostaria de mais uma vez solicitar a ajuda dos companheiros.

O caso é o seguinte, tenho uma tabela onde realizo o cadastro de clientes e para cada código de cliente é aberto um processo que entrará num ciclo sequencial de 7 fases. Mas a questão aqui não envolve os ciclos que cada processo e sim o fato de que estes processos podem e poderão ter alguns status que indicara o motivo da pendências dos mesmos e eu preciso apresentar num mesmo Grid todos os processos abertos que possuam as pendências especificadas ou não. Para exemplificar e tornar mais claro uma possível solução, tenho o seguinte cenário:

Selecionar tudo


TABELA CLIENTE:

COD_CLI  NOME

   X     ABC
   Y     DEF

TABELA PROCESSO_CLIENTE

COD_PROCESSO  DESC_PROCESSO   CLIENTE 
     
     1             XYZ           X
     2             ZYX           Y

TABELA PENDENCIA

COD_PENDENCIA MOTIVO     COD_PROCESSO

     1        MOTIVO A        1

Ou seja, tentando práticar uma modelagem criei uma tabela para atender a segunda forma normal, especificando a tabela PENDÊNCIA ao invés de criar uma coluna PENDÊNCIA na tabela PROCESSO_CLIENTE, assumindo que em diversos momentos vários processos poderão ter vários motivos de pendência (por favor me corrijam se tiver errado).

Acontece que seguindo esta modelagem, ao tentar listar todos os processos dos clientes que tenham ou não alguma pendência especificada me é retornado apenas os processos que possuem sua identificação referenciada na tabela de pendencia, exemplo:

Selecionar tudo



SELECT C.*, PC.DESCR_PROCESSO, P.MOTIVO
FROM CLIENTE C, PROCESSO_CLIENTE PC, PENDENCIA P
WHERE C.COD_CLIENTE   = PC.COD_CLIENTE
  AND PC.COD_PROCESSO = P.COD_PROCESSO

Resultado:

COD_PROCESSO  DESC_PROCESSO   CLIENTE  DESCR_PROCESSO  MOTIVO
     
     1             XYZ           X          XYZ        MOTIVO A

Neste caso só me é retornado o processo com uma pendência em aberto, e eu preciso trazer todos os outros clientes que também não possuem as pendências especificadas.
Tinho
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 317
Registrado em: Seg, 16 Nov 2009 4:50 pm
Localização: São Paulo - SP

Eu consegui fazer algo semelhante utilizando o UNION ALL, ou seja, utilizo uma query que me retorna os registros dos CLIENTES que tenham processos com pendência e uma outra query que me retorne os registros dos CLIENTES que tenham processos sem pendência, junto o resultado das duas, depois utlizo um SELECT "exterior" relacionando as tabela de PROCESSOS com a de PENDENCIA onde mando retornar os PROCESSOS_CLIENTES que não contenham referência na tabela PENDENCIA, porém neste caso o MOTIVO da PENDENCIA é replicado para todos os registros do SELECT retornado mesmo que não tenham MOTIVO relacionado na tabela de pendência, e como a coluna MOTIVO só existe na query que me retornará as PENDENCIAS no primeiro SELECT eu criei uma coluna "virtual" com valor nulo, de qualquer maneira o resultado é duplicado, repetindo duas vezes o mesmo registro, sendo que um com pendência e outro sem:

Ficou mais ou menos assim:

Selecionar tudo


SELECT DISTINCT 
  A."COD",
  A."NOME",
  A."IDPROC",
  A."DESCR",
  P1.MOTIVO
FROM 
(
  SELECT C.COD_CLIENTE     AS "COD", 
         C.NOME		   AS "NOME", 
	 PC.DESCR_PROCESSO AS "IDPROC", 
         NULL "MOTIVO"	   AS "DESCR"
  FROM CLIENTE C, 
       PROCESSO_CLIENTE PC, 
  WHERE C.COD_CLIENTE   = PC.COD_CLIENTE
  UNION ALL
  SELECT C.COD_CLIENTE     AS "COD", 
         C.NOME		   AS "NOME", 
	 PC.DESCR_PROCESSO AS "IDPROC", 
         P.MOTIVO	   AS "DESCR"
  FROM CLIENTE C, PROCESSO_CLIENTE PC, PENDENCIA P
  WHERE C.COD_CLIENTE   = PC.COD_CLIENTE
    AND PC.COD_PROCESSO = P.COD_PROCESSO
)A,PENDENCIA P1,
WHERE P1.COD_PROCESSO NOT IN (SELECT PC1.COD_PROCESSO FROM PROCESSO_CLIENTE PC1)

Resultado

COD_PROCESSO  DESC_PROCESSO   CLIENTE  DESCR_PROCESSO  MOTIVO
     
     1             XYZ           X          ---        ------
     1             XYZ           X          XYZ        MOTIVO A
     2             ZYX           Y          ---        ------


Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Olá,

Creio que você precisa utilizar outer join nesse caso, representado em sintaxe ANSI por LEFT [OUTER] JOIN:

Selecionar tudo

SELECT c.*, pc.descr_processo, p.motivo
  FROM cliente c
  JOIN processo_cliente pc ON c.cod_cliente = pc.cod_cliente
  LEFT JOIN pendencia p ON pc.cod_processo = p.cod_processo;
Tinho
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 317
Registrado em: Seg, 16 Nov 2009 4:50 pm
Localização: São Paulo - SP

É eu já havia pensado e até tentado fazer e utilizar outras opções de JOINS porém não estava obtendo êxito porque esta errando a sintaxe, como pude verificar posteriormente aqui no fórum mesmo. Mas obrigado, por reforçar a idéia, amanhã vou tentar resolver utilizando esta solução.

Grato,
Tinho
Rank: DBA Sênior
Rank: DBA Sênior
Mensagens: 317
Registrado em: Seg, 16 Nov 2009 4:50 pm
Localização: São Paulo - SP

Perfeito cara! Você me salvou!

Obrigado.
Responder
  • Informação
  • Quem está online

    Usuários navegando neste fórum: Nenhum usuário registrado e 8 visitantes