none
Subquery desconsidera filtro RRS feed

  • Pergunta

  • Caros companhanheiros, agradeço desde já vossas ajudas!

    Tenho um SELECT com a seguinte estrutura:

    --######################

    SELECT

    vd.vendedor

    ,(

    SELECT it_obj.valor FROM item_objetivo it_obj

     

    JOIN objetivo obj ON obj.cod= it_obj.cod AND it_obj.vendedor= vd.vendedor

    AND obj.mes_ref>= '2011-06-01'

    JOIN fabricante fb ON fb.cod_fabric = it_obj.cod_fabric AND fb.nome='FABRICANTE A') AS 'FABRICANTE A'

     

    ,( SELECT it_obj.valor FROM item_objetivo it_obj

     

    AND obj.mes_ref>= '2011-06-01'

    JOIN fabricante fb ON fb.cod_fabric = it_obj.cod_fabric AND fb.nome= 'FABRICANTE B') AS 'FABRICANTE B'

    JOIN objetivo obj ON obj.cod= it_obj.cod AND it_obj.vendedor= vd.vendedor

     

     

    FROM

    vendedor vd

    ORDER

    BY

    vd

    .cd_vend

     

    --#################

    Acontece que com todos os fabricantes dá certo, mas só determinado fabricante a subquery retorna valores de outro mês e desconsidera o filtro do mês referência.Já usei o filtro no WHERE e também deu erro.

    Alguém já passou por algo parecido?

    segunda-feira, 20 de junho de 2011 15:32

Respostas

  • Boa Noite, Davi Igor!

    Espero poder te ajudar a resolver esse problema.

    Como não temos a tabela aqui, peço a você que comece a verificar pelo início:

    1. Verifique como está as colunas retornadas dos registros que você está buscando nesse determinado fabricante. Este teste é para saber se para esse período informado realmente existe algum registro ou se as datas pode estar com valor NULL, etc. Seria similar ao código abaixo:

    select
     obj.mes_ref,
     it_obj.cd_vend,
     it_obj.cd_objetivo,
     it_obj.cd_fabric,
     *
    from
     item_objetivo       it_obj
     left join objetivo      obj
      on it_obj.cd_objetivo  =  obj.cd_objetivo
     left join fabricante fb
      on it_obj.cd_fabric   =  fb.cd_fabric
    where
     fb.sigla      =  'fabricanteComProblemaNaConsulta' 
    


     

    2. Um dica: evite com todas as suas forças utilizar subselect. Esse tipo de recurso apesar de ser uma solução aparentemente mais simples na verdade pode se tornar um gargalo em seu servidor de banco de dados. Imagine que se sua consulta retorna 10 registros, para cada registro o SQL Server ainda faz mais duas consultas, ou seja, mais 20 consultas. Agora imagine isso em média escala, numa consulta que te retorne 40.000 registros. Seriam mais 80.000 consultas, além de todo o processamento e memória para obter os 40.000 iniciais.

    E de preferência, tenta usar INNER JOIN também para unir as tabelas. Além da elegância e organização do código, é uma orientação da Microsoft o uso de JOIN para junção de tabelas. Você pode ler um pouco mais sobre JOIN no seguinte link: http://msdn.microsoft.com/pt-br/library/ms191472.aspx

     

    Portanto, sugiro que você altere sua consulta para algo assim(essa consulta faz o mesmo que a sua está fazendo):

     

    SET DateFormat YMD
    
    SELECT
     vd.cd_vend,
     vd.vendedor,
     it_obj1.valor as 'Fabricante 1',
     it_obj2.valor as 'Fabricante 2'
    FROM
     vendedor vd
     inner join (
       item_objetivo    it_obj1
       inner join objetivo   obj1
       on it_obj1.cd_objetivo = obj1.cd_objetivo
       AND obj1.mes_ref  >= '2011-06-01 00:00:00.000'
       inner join fabricante   fb1
       on it_obj1.cd_fabric = fb1.cd_fabric
      )
     on it_obj1.cd_vend  = vd.cd_vend
     inner join (
       item_objetivo    it_obj2
       inner join objetivo   obj2
       on it_obj2.cd_objetivo = obj2.cd_objetivo
       AND obj.mes_ref  >= '2011-06-01 00:00:00.000'
       inner join fabricante   fb2
       on it_obj2.cd_fabric = fb2.cd_fabric
      )
     on it_obj2.cd_vend  = vd.cd_vend  
    WHERE
     fb1.Sigla = 'fab1'
     AND fb2.Sigla = 'fab2'
    ORDER BY
     vd.cd_vend
    

    Apesar de parecer um pouco, nesta consulta os valores só são consultados uma única vez para trazer todos os registros. E isso faz muita diferença em uma grande tabela, com um número razoável de pessoas realizando a mesma consulta.

     

    Quando você retornar com alguma notícia sobre o primeiro ponto, vamos prosseguir para verificarmos o que fazer, ok?!

    Seria bom também conhecer a estrutura da tabela ( os campos, tipos e tamanhos). Para você nos informar isso bastar executar o código abaixo no seu SQL Server para as tabelas envolvidas nos informando o retorno:

    sp_help tabela
    Espero estar ajudando em algo.

     


    Fredy Esmeraldo
    Microsoft MCP, MCTS SQL Server 2008 Implementation and Maintenance
    Visite o meu blog: http://fredyesmeraldo.wordpress.com
    Me siga no twitter: @fredyesmeraldo
    **Ajude a melhorar o sistema de busca do fórum.Marque a(s) resposta(s) que foram úteis**

    • Editado Fredy Esmeraldo terça-feira, 21 de junho de 2011 04:32 Acréscimo de informações na primeira consulta
    • Sugerido como Resposta Eder Costa terça-feira, 28 de junho de 2011 19:12
    • Marcado como Resposta Eder Costa segunda-feira, 4 de julho de 2011 14:47
    terça-feira, 21 de junho de 2011 04:24

Todas as Respostas

  • Acho que deve ser utilizada o WHERE para todos os filtros.

    Experimente desta forma:

     

     

    SELECT
    
    vd.vendedor
    
    ,(
    
    SELECT it_obj.valor FROM item_objetivo it_obj 
    
     
    JOIN objetivo obj ON obj.cod= it_obj.cod
    
    
    JOIN fabricante fb ON fb.cod_fabric = it_obj.cod_fabric 

    WHERE

    it_obj.vendedor= vd.vendedor AND
    obj.mes_ref>= '2011-06-01' AND
    fb.nome='FABRICANTE A') AS 'FABRICANTE A'



    ,( SELECT it_obj.valor FROM item_objetivo it_obj
    JOIN objetivo obj ON obj.cod= it_obj.cod
    JOIN fabricante fb ON fb.cod_fabric = it_obj.cod_fabric

    WHERE

    it_obj.vendedor= vd.vendedor AND
    obj.mes_ref>= '2011-06-01' AND

    fb.nome= 'FABRICANTE B') AS 'FABRICANTE B'
    FROM vendedor vd ORDER BY vd.cd_vend

     

     

     

     Espero que seja útil.


    Assinatura: Imoveis comerciais em Guarulhos

    segunda-feira, 20 de junho de 2011 16:18
  • Davi, não entendi muito bem o seu problema.

    Acho que seria mais fácil você nos dizer o que gostaria de retornar em seu Select, ou seja, qual o seu objetivo com essa instrução.

    Assim tentaremos lhe apresentar a melhor solução.


    Roberson Ferreira - Database Developer

    Se esta sugestão for útil, por favor, classifique-a como útil.
    Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.

    segunda-feira, 20 de junho de 2011 16:48
    Moderador
  • Cara!

     

    Joguei todas as condições no Where, mas nada.A subquery retorna os outros meses, continuando a não obedecer o filtro de período.

    Desta vez, testei até com as condições de ligação da tabela, como padrão ANSI.

    O Subselect ficou com as tabelas depois do FROM assim: FROM vendedor vd,fabricante fb,objetivo obj, item_objetivo it_obj WHERE obj.cod_obj = it_obj.cod_obj ETC...

    O engraçado, é que a Subquery só não obedece para um fabricante.Testei com outros e tudo ocorreu bem em qualquer lógica usada.Este em nenhuma que tentei.

    Será que pode ter algo a ver com índice ou algo similar?

     

    segunda-feira, 20 de junho de 2011 17:44
  • Roberto,

    Tenho as tabelas de objetivo, item_objetivo, vendedor  e fabricante.

    Na tabela objetivo tenho o campo mes_referencia, tenho que buscar os valores dos objetivos dos vendedores nessas tabelas de acordo com o mês atual e fabricante.Meu interesse é uma consulta que retorne os dados dessa maneira:

    VENDEDOR      OBJ_FABRIC_A_R$   OBJ_FABRIC_B_R$   OBJ_FABRIC_C_R$

    JOAO              1000                      2000                     500

    usando o CASE no lugar das Subquerys os dados vinham assim

    VENDEDOR      OBJ_FABRIC_A_R$   OBJ_FABRIC_B_R$   OBJ_FABRIC_C_R$

    JOAO              NULL                     2000                      NULL

    JOAO              NULL                     NULL                      500

    JOAO              1000                     NULL                      NULL

     

     

    Subquery foi a solução que encontrei pra isso.Mas somente com 1 fabricante não dá certo!A subquery não respeita o mês de filtragem retornado os valores de outros meses.Isso é porque executei a Subquery separada.

    Não sei se ajuda, mas eu salvei a mesma subquery e ela funciona executando sozinha quando eu reinicio o SQLSERVER, mas se eu usar ela dentro da query toda, daí da erro e não funciona nem sozinha mais.Pode ser sujeira de cache?

    segunda-feira, 20 de junho de 2011 18:05
  • Davi, você teria como postar a estrutura dessas tabelas por favor?
    Roberson Ferreira - Database Developer

    Se esta sugestão for útil, por favor, classifique-a como útil.
    Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.

    segunda-feira, 20 de junho de 2011 19:03
    Moderador
  • SELECT
    
    vd.cd_vend
    ,vd.vendedor
    ,(		SELECT it_obj.valor
    		FROM item_objetivo it_obj, objetivoobj,fabricante fb
    		WHERE 
    		obj.mes_ref >= '01/06/2011 00:00:00'
    		AND it_obj.cd_vend = vd.cd_vend 
    		AND fb.sigla='fab1'
    		AND obj.cd_objetivo = it_obj.cd_objetivo		AND	fb.cd_fabric = it_obj.cd_fabric
    ) AS 'Fabricante 1'
    
    
    ,(		SELECT it_obj.valor
    		FROM item_objetivo it_obj, objetivoobj,fabricante fb
    		WHERE 
    		obj.mes_ref >= '01/06/2011 00:00:00'
    		AND it_obj.cd_vend = vd.cd_vend 
    		AND fb.sigla='fab2'
    		AND obj.cd_objetivo = it_obj.cd_objetivo		AND	fb.cd_fabric = it_obj.cd_fabric
    ) AS 'Fabricante 2'
    
    
    
    
    FROM
    vendedor vd
    ORDER BY
    vd.cd_vend
    
    segunda-feira, 20 de junho de 2011 19:28
  • Lembrando que a data está ok!É que usei 'set dateformat dmy', também testei com a data padrão e nada!
    segunda-feira, 20 de junho de 2011 19:30
  • Mas o idioma do seu SQL é inglês? As datas de referência estão armazenadas na tabela em formato americano?

    Se sim, teste sem usar o Set DateFormat e passando a data em formato americano mesmo.

    Outro detalhe: reparei que o campo que você está usando no filtro chama-se "mes_ref". Este campo armazena realmente uma data, em formato mm/dd/yyyy? Pelo nome parece que só armazena o mês.


    Roberson Ferreira - Database Developer

    Se esta sugestão for útil, por favor, classifique-a como útil.
    Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.

    segunda-feira, 20 de junho de 2011 22:28
    Moderador
  • Boa Noite, Davi Igor!

    Espero poder te ajudar a resolver esse problema.

    Como não temos a tabela aqui, peço a você que comece a verificar pelo início:

    1. Verifique como está as colunas retornadas dos registros que você está buscando nesse determinado fabricante. Este teste é para saber se para esse período informado realmente existe algum registro ou se as datas pode estar com valor NULL, etc. Seria similar ao código abaixo:

    select
     obj.mes_ref,
     it_obj.cd_vend,
     it_obj.cd_objetivo,
     it_obj.cd_fabric,
     *
    from
     item_objetivo       it_obj
     left join objetivo      obj
      on it_obj.cd_objetivo  =  obj.cd_objetivo
     left join fabricante fb
      on it_obj.cd_fabric   =  fb.cd_fabric
    where
     fb.sigla      =  'fabricanteComProblemaNaConsulta' 
    


     

    2. Um dica: evite com todas as suas forças utilizar subselect. Esse tipo de recurso apesar de ser uma solução aparentemente mais simples na verdade pode se tornar um gargalo em seu servidor de banco de dados. Imagine que se sua consulta retorna 10 registros, para cada registro o SQL Server ainda faz mais duas consultas, ou seja, mais 20 consultas. Agora imagine isso em média escala, numa consulta que te retorne 40.000 registros. Seriam mais 80.000 consultas, além de todo o processamento e memória para obter os 40.000 iniciais.

    E de preferência, tenta usar INNER JOIN também para unir as tabelas. Além da elegância e organização do código, é uma orientação da Microsoft o uso de JOIN para junção de tabelas. Você pode ler um pouco mais sobre JOIN no seguinte link: http://msdn.microsoft.com/pt-br/library/ms191472.aspx

     

    Portanto, sugiro que você altere sua consulta para algo assim(essa consulta faz o mesmo que a sua está fazendo):

     

    SET DateFormat YMD
    
    SELECT
     vd.cd_vend,
     vd.vendedor,
     it_obj1.valor as 'Fabricante 1',
     it_obj2.valor as 'Fabricante 2'
    FROM
     vendedor vd
     inner join (
       item_objetivo    it_obj1
       inner join objetivo   obj1
       on it_obj1.cd_objetivo = obj1.cd_objetivo
       AND obj1.mes_ref  >= '2011-06-01 00:00:00.000'
       inner join fabricante   fb1
       on it_obj1.cd_fabric = fb1.cd_fabric
      )
     on it_obj1.cd_vend  = vd.cd_vend
     inner join (
       item_objetivo    it_obj2
       inner join objetivo   obj2
       on it_obj2.cd_objetivo = obj2.cd_objetivo
       AND obj.mes_ref  >= '2011-06-01 00:00:00.000'
       inner join fabricante   fb2
       on it_obj2.cd_fabric = fb2.cd_fabric
      )
     on it_obj2.cd_vend  = vd.cd_vend  
    WHERE
     fb1.Sigla = 'fab1'
     AND fb2.Sigla = 'fab2'
    ORDER BY
     vd.cd_vend
    

    Apesar de parecer um pouco, nesta consulta os valores só são consultados uma única vez para trazer todos os registros. E isso faz muita diferença em uma grande tabela, com um número razoável de pessoas realizando a mesma consulta.

     

    Quando você retornar com alguma notícia sobre o primeiro ponto, vamos prosseguir para verificarmos o que fazer, ok?!

    Seria bom também conhecer a estrutura da tabela ( os campos, tipos e tamanhos). Para você nos informar isso bastar executar o código abaixo no seu SQL Server para as tabelas envolvidas nos informando o retorno:

    sp_help tabela
    Espero estar ajudando em algo.

     


    Fredy Esmeraldo
    Microsoft MCP, MCTS SQL Server 2008 Implementation and Maintenance
    Visite o meu blog: http://fredyesmeraldo.wordpress.com
    Me siga no twitter: @fredyesmeraldo
    **Ajude a melhorar o sistema de busca do fórum.Marque a(s) resposta(s) que foram úteis**

    • Editado Fredy Esmeraldo terça-feira, 21 de junho de 2011 04:32 Acréscimo de informações na primeira consulta
    • Sugerido como Resposta Eder Costa terça-feira, 28 de junho de 2011 19:12
    • Marcado como Resposta Eder Costa segunda-feira, 4 de julho de 2011 14:47
    terça-feira, 21 de junho de 2011 04:24
  • Davi,

    os teus clientes estão funcionando no mesmo servidor?

    como é que os clientes acessam esse banco?

    porque pode ser que o servidor do teu cliente que está colocando a data no formato ingles.


    Midana Fernandes Sana Fortaleza - CE Brasil
    terça-feira, 21 de junho de 2011 20:24
  • Pessoal, desculpem a falta de tempo para responder, agradeço mesmo a atenção!

    Os campos de data são SMALLDATETIME, ou seja, armazenam dia,mês,ano e hora.

    sábado, 25 de junho de 2011 03:02
  • Esse é um BD interno e usado por um ERP alugado.Atualmente somente eu faço consultas nesse BD e somente consultas.Fiz um minicurso para conhecer melhor as tabelas, mass só foram usadas as tabelas essenciais e na hora você não tem como questionar, porque essas necessidades aparecem com o dia a dia.E pelo que conheço o SET DATEFORMAT usa o formato que você colocar posteriormente ex:dmy e pega todo o código abaixo do comando.Se eu estiver errado, me corrijam, mas já usei em muitas rotinas assim.

    sábado, 25 de junho de 2011 03:08
  • Opa!!!

    Fred, muito interessante sua posição com os Joins, pois eu nunca tinha usado desta forma e de qualquer maneira, adotarei para futuras queryes.Esses dias atrás tive um problema com JOINs.Precisava retornar todos os campos da primeira tabela e não estava dando certo com LEFT JOIN, daí vi um post que disse pra colocar os filtros do WHERE nos JOINs ex: JOIN tbl1 on c = tb2.c AND ativo=1, assim rodou.Então estou esperto com JOINs.

    Assim que testar, posto pra todos.

    sábado, 25 de junho de 2011 03:19