none
Query Complexa RRS feed

  • Pergunta

  • Pessoal,

     

    Tenho a seguinte query já desenvolvida:

     

    --***********************************************************************************

    SELECT c.vc_pagamento_tipo, b.id_evento_preco, b.it_parcela, b.dt_validade, b.mn_preco

    FROM ls1_tb_evento_preco_pagamento_tipo AS a

    INNER JOIN ls1_tb_evento_preco AS b ON a.id_evento_preco = b.id_evento_preco

    INNER JOIN ls1_tb_pagamento_tipo AS c ON a.id_pagamento_tipo = c.id_pagamento_tipo

    WHERE b.id_evento_categoria = 65 AND c.id_forma_pagto =3

    AND b.dt_validade IN

    (

    SELECT DISTINCT dt_validade

    FROM

    (

    SELECT

    it_parcela,

    MIN(dt_validade) AS dt_validade

    FROM ls1_tb_evento_preco WITH(NOLOCK)

    WHERE id_evento_categoria = 65

    AND CONVERT(VARCHAR(10), dt_validade, 120) >= CONVERT(VARCHAR(10), GETDATE(), 120)

    GROUP BY it_parcela

    ) AS datas

    )

    ORDER BY b.dt_validade, b.id_evento_preco DESC

    --***********************************************************************************

     

    O Resultado que ela me retorna é o seguinte:

     

    --***********************************************************************************

     

    vc_pagamento_tipo  id_evento_preco it_parcela   dt_validade               mn_preco

    -------------------------- -------------------- ------------- --------------------------- ----------

    Mastercard               46                        8               2007-11-10 00:00:00  1200,00

    Diners                      46                        8               2007-11-10 00:00:00  1200,00

    Visa                         34                       10              2007-11-10 00:00:00  999,99

    Diners                      34                       10              2007-11-10 00:00:00  999,99

    Mastercard              34                        10              2007-11-10 00:00:00  999,99

     

    --***********************************************************************************

     

    Eu precisaria de alguma forma, agrupar e exibir somente os resultados do ultimo id_evento_preco (o mairo, no caso, o id 46 para Master e Dinner e o id 34 pra Visa, pois ele não tem registro com o ID 46)

     

    Não sei se consegui explanar com eficiencia o meu problema, mas o resultado da query teria que ficar assim:

     

    --***********************************************************************************

     

    vc_pagamento_tipo  id_evento_preco it_parcela   dt_validade               mn_preco

    ------------------------- --------------------- ------------- ------------------------- -----------

    Mastercard                46                        8               2007-11-10 00:00:00  1200,00

    Diners                       46                        8               2007-11-10 00:00:00  1200,00

    Visa                          34                       10              2007-11-10 00:00:00  999,99

     

    --***********************************************************************************

     

    A estrutura das tabelas é como a seguinte:

     

    ls1_tb_evento_preco

    ------------------------------

    id_evento_preco

    id_evento_categoria

    it_parcela

    dt_validade

    mn_preco

     

    ls1_tb_evento_preco_pagamento_tipo

    -------------------------------------------------------

    id_evento_preco_pagamento_tipo

    id_evento_preco

    id_pagamento_tipo

     

    ls1_tb_pagamento_tipo

    ----------------------------------

    id_pagamento_tipo

    id_forma_pagto

    vc_pagamento_tipo

     

    ls1_tb_forma_pagto

    ----------------------------

    id_forma_pagto

    vc_forma_pagto

     

     

    PS: Se alguém tiver alguma idéia para melhroar a query em questões de desempenho também será muito útil.

     

    Obrigado.

    quarta-feira, 7 de novembro de 2007 18:44

Respostas

  • carlos,

     

    Criei um exemplo aqui básico em cima do que aparece na sua consulta e o que gostaria de retornar. Cara da uma olhada e ve se te serve pra alguma coisa. Se tiver dúvida em alguma coisa pergunta que te explico. Vamos torcer para que de certo.

     

    Abraço,

     

    chapolin.rio@gmail.com

     

     

    CREATE TABLE #TESTE

    (

    nome varchar(20),

    codigo int,

    parcelas int,

    data datetime,

    preco decimal(10,2)

    )

     

    INSERT INTO #TESTE VALUES('Mastercard',46,8,'2007-11-10 00:00:00',1200.00)

    INSERT INTO #TESTE VALUES('Diners',46,8,'2007-11-10 00:00:00',1200.00)

    INSERT INTO #TESTE VALUES('Visa',34,10,'2007-11-10 00:00:00',999.99)

    INSERT INTO #TESTE VALUES('Diners',34,10,'2007-11-10 00:00:00',999.99)

    INSERT INTO #TESTE VALUES('Mastercard',34,10,'2007-11-10 00:00:00',999.99)

     

    SELECT SUBQUERY.*,

       #TESTE.parcelas,

      #TESTE.preco

      FROM

    (SELECT nome,

    mAX(codigo)codigo ,

    data

    FROM #TESTE

    GROUP BY nome,

    data

    )SUBQUERY

    INNER JOIN #TESTE

    ON #TESTE.codigo = SUBQUERY.codigo

    AND #TESTE.nome = SUBQUERY.nome

     

    --SELECT * FROM #TESTE

    DROP TABLE #TESTE

    quarta-feira, 7 de novembro de 2007 19:50

Todas as Respostas

  • Carlos,

     

    Olhando rápido da uma olhada no exemplo que estou postanto aqui. Cara eu não sei se vai dar certo, mas me confirma o seguinte: Se vc não usar o preço no Group vai dar erro e se usar vão repetir os registros pois os preços são diferentes correto? Tenta aí  e me diz.

     

    SELECT c.vc_pagamento_tipo, MAX(b.id_evento_preco), b.it_parcela, b.dt_validade, b.mn_preco

    FROM ls1_tb_evento_preco_pagamento_tipo AS a

    INNER JOIN ls1_tb_evento_preco AS b ON a.id_evento_preco = b.id_evento_preco

    INNER JOIN ls1_tb_pagamento_tipo AS c ON a.id_pagamento_tipo = c.id_pagamento_tipo

    WHERE b.id_evento_categoria = 65 AND c.id_forma_pagto =3

    AND b.dt_validade IN

    (

    SELECT DISTINCT dt_validade

    FROM

    (

    SELECT

    it_parcela,

    MIN(dt_validade) AS dt_validade

    FROM ls1_tb_evento_preco WITH(NOLOCK)

    WHERE id_evento_categoria = 65

    AND CONVERT(VARCHAR(10), dt_validade, 120) >= CONVERT(VARCHAR(10), GETDATE(), 120)

    GROUP BY it_parcela

    ) AS datas

    )

    GROUP BY c.vc_pagamento_tipo, b.it_parcela, b.dt_validade, b.mn_preco

    ORDER BY b.dt_validade, b.id_evento_preco DESC

     

    Abraço,

     

    chapolin.rio@gmail.com

    quarta-feira, 7 de novembro de 2007 19:12
  • Chapolin,

     

    Eu testei, mas é exatamente o que vc falou, se não usar o preço no Group vai dar erro e se usar vão repetir os registros pois os preços são diferentes

     

    de qualquer forma obrigado, vou tentando outras gambiarras enquanto isso.

     

     

    quarta-feira, 7 de novembro de 2007 19:23
  • carlos,

     

    Criei um exemplo aqui básico em cima do que aparece na sua consulta e o que gostaria de retornar. Cara da uma olhada e ve se te serve pra alguma coisa. Se tiver dúvida em alguma coisa pergunta que te explico. Vamos torcer para que de certo.

     

    Abraço,

     

    chapolin.rio@gmail.com

     

     

    CREATE TABLE #TESTE

    (

    nome varchar(20),

    codigo int,

    parcelas int,

    data datetime,

    preco decimal(10,2)

    )

     

    INSERT INTO #TESTE VALUES('Mastercard',46,8,'2007-11-10 00:00:00',1200.00)

    INSERT INTO #TESTE VALUES('Diners',46,8,'2007-11-10 00:00:00',1200.00)

    INSERT INTO #TESTE VALUES('Visa',34,10,'2007-11-10 00:00:00',999.99)

    INSERT INTO #TESTE VALUES('Diners',34,10,'2007-11-10 00:00:00',999.99)

    INSERT INTO #TESTE VALUES('Mastercard',34,10,'2007-11-10 00:00:00',999.99)

     

    SELECT SUBQUERY.*,

       #TESTE.parcelas,

      #TESTE.preco

      FROM

    (SELECT nome,

    mAX(codigo)codigo ,

    data

    FROM #TESTE

    GROUP BY nome,

    data

    )SUBQUERY

    INNER JOIN #TESTE

    ON #TESTE.codigo = SUBQUERY.codigo

    AND #TESTE.nome = SUBQUERY.nome

     

    --SELECT * FROM #TESTE

    DROP TABLE #TESTE

    quarta-feira, 7 de novembro de 2007 19:50
  • Chapolin,

     

    Deu certo cara!, ficou assim:

     

    --**************************************************************************************************************

     

    SELECT a.vc_pagamento_tipo, a.dt_validade, a.id_evento_preco, b.it_parcela, b.mn_preco

    FROM

    (

    SELECT c.vc_pagamento_tipo, b.dt_validade, MAX(b.id_evento_preco) AS id_evento_preco

    FROM ls1_tb_evento_preco_pagamento_tipo AS a

    INNER JOIN ls1_tb_evento_preco AS b ON a.id_evento_preco = b.id_evento_preco

    INNER JOIN ls1_tb_pagamento_tipo AS c ON a.id_pagamento_tipo = c.id_pagamento_tipo

    WHERE b.id_evento_categoria = 65 AND c.id_forma_pagto =3

    AND b.dt_validade IN

    (

    SELECT DISTINCT dt_validade

    FROM

    (

    SELECT

    it_parcela,

    MIN(dt_validade) AS dt_validade

    FROM ls1_tb_evento_preco WITH(NOLOCK)

    WHERE id_evento_categoria = 65

    AND CONVERT(VARCHAR(10), dt_validade, 120) >= CONVERT(VARCHAR(10), GETDATE(), 120)

    GROUP BY it_parcela

    ) AS datas

    )

    GROUP BY c.vc_pagamento_tipo, b.dt_validade

    ) AS a

    INNER JOIN ls1_tb_evento_preco AS b ON a.id_evento_preco = b.id_evento_preco

     

    --**************************************************************************************************************

     

    A minha torcida agora é para que o desempenho não fique muito defasado, devido ao excesso de subquerys, mas valeu!, funcionar vai, qq coisa eu tento fazer uma view depois.

     

    Obrigado!

     

    quarta-feira, 7 de novembro de 2007 20:10
  • Opa,

     

    Carlos obrigado pelo retorno.

    Cara a respeito de desempenho pode ser que não seja dos melhores por se tratar de subquerys, porém acredito que a diferença não seja tão assustadora assim. No caso de vc construir um View seria algo interessante, pois como uma procedure, se não me engano, a view fica pré-compilada no banco, sendo assim o ganho de desempenho é bem grande em relação a um query normal.

    Bem acho que é isso. Quando precisar estamos aí!!

     

    Abraço,

     

    chapolin.rio@gmail.com

    quarta-feira, 7 de novembro de 2007 20:21
  • Chapolin,

     

    O que você acha de utilizar uma table temporária ou até mesmo criar uma stored procedure, pois desta forma, utilizaremos o plano de execução do SQL Server.

     

    quinta-feira, 8 de novembro de 2007 10:59
  • Junior,

     

    Eu particularmente nos meus projetos não utilizo querys, somente, por mais simples que seja, procedure. No caso de uma criação de procedure com toda a certeza eu trabalharia com Tabelas temporárias pq acredito que seja uma forma mais ágil de trabalho. Porém nosso amigo pediu uma query e depois suegeriu um View então dei um exemplo conforme pedido e falei o pq da view também. MAs concordo em nº, genero e grau com vc.. Nada melhor do que uma procedure em se tratando de banco.

    Agora me responde uma coisa:

    AS Views não utilizam o plano de execução do SQL SERVER?? Somente as Procedures e Functions?!?

     

    Obrigado e um grande abraço,

     

    chapolin.rio@gmail.com

    quinta-feira, 8 de novembro de 2007 13:01
  • Chapolin,

     

    As views, não utilizam plano de execução.

     

    Concordo com você em sua forma de trabalho.

    quinta-feira, 8 de novembro de 2007 13:23
  • Junior,

     

    Obrigado pelo retorno. Sempre bom saber dessas informações.

     

    Abraço.

     

    Chapolin.rio@gmail.com

     

     

     

     

     

    quinta-feira, 8 de novembro de 2007 13:28
  •  

    Obrigado pela interação de todos,

     

    Só para constar, eu fiz uma view para listar os dados de forma macro, por causa das subquerys, e depois fiz uma proc para receber os parametros e realizar a query.

     

    Vocês acham que essa é a melhor forma dentro desse contexto?

     

    Grato!


     

    quinta-feira, 8 de novembro de 2007 13:37
  • Carlos,

     

    Você pode colocar essa query diretamem numa proc e usar parãmetros sem precisar de um View. Se tratando de proc toda ela já estará pré compilada, sendo assim ganho de performace. Sendo que como vc já tem um View e uma proc é que chama essa view também terá um ganho. Só não sei te informar se o ganho será maior do que no caso de colocar diretamente a query. Deixemos o próximo, rsrsrsr, responder essa aí que até eu vou ganhar com essa sua ótima pergunta.

     

    Abraço,

     

    chapolin.rio@gmail.com

    quinta-feira, 8 de novembro de 2007 13:44
  •  

    Oi pessoal, só um comentário rápido...

    Todas as consultas no SQL Server devem possuir um plano de execução para serem passíveis de ser executada pela engine do SQL Server. Quando estamos utilizando uma view em uma consulta (vamos imaginar que fazemos um join com uma outra tabela), o que o SQL Server faz é pegar a definição da view e criar um plano de execução único, juntamente com o join da consulta de exemplo.

    Após a execução da consulta o SQL Server coloca o plano na cache de procedimentos (talvez parametrizado) que poderá ou não ser reutilizado no futuro.

     

    Abraços

    Luciano Moreira

    terça-feira, 13 de novembro de 2007 15:43
  •  

    Carlos,

     

    Complementando a resposta do Luciano, eu simplesmente evito usar subquerys. Tente trocar por JOINs. Por exemplo:

     

    SELECT *

    FROM TabelaA A

    INNER JOIN (

    SELECT CampoA, CampoB

    FROM TabelaB

    ) B ON A.CampoID = B.CampoID

     

    Funciona basicamente como o IN, mas tem desempenho melhor.

     

    Abraço

    terça-feira, 13 de novembro de 2007 22:07