18/11/2005

Select com periodos independentes

Colegas,

Criei uma consulta com um select principal agrupando por codigo de produto e dentro deste select eu possuo 10 sub-selects que equivalem a periodos diferentes dentro da faixa de datas do periodo do select principal e cada sub-select desse me retorna um valor total de um periodo relacionado pelo codigo de material com o select principal, segue ex: da query abaixo:

SELECT P.D2_COD CODIGO, (SELECT SUM(P1.D2_TOTAL) TOTAL1 FROM SD2010 P1 WITH(INDEX=SD20106) , SF4010 SF41 WHERE P.D2_COD=P1.D2_COD AND P1.D2_EMISSAO BETWEEN ´20050701´ AND ´20050701´ AND P1.D_E_L_E_T_ <> ´*´ AND P1.D2_TP IN (´PA´,´MR´) AND P1.D2_TES=SF41.F4_CODIGO AND SF41.D_E_L_E_T_ <> ´*´ AND SF41.F4_DUPLIC=´S´ AND SF41.F4_ESTOQUE<>´´ ) PERIODO1, (SELECT SUM(P2.D2_TOTAL) AS TOTAL2 FROM SD2010 P2 WITH(INDEX=SD20106) , SF4010 SF42 WHERE P.D2_COD=P2.D2_COD AND P2.D2_EMISSAO BETWEEN ´20050702´ AND ´20050702´ AND P2.D_E_L_E_T_ <> ´*´ AND P2.D2_TP IN (´PA´,´MR´) AND P2.D2_TES=SF42.F4_CODIGO AND SF42.D_E_L_E_T_ <> ´*´ AND SF42.F4_DUPLIC IN (´S´) AND SF42.F4_ESTOQUE IN (´S´,´N´) ) AS PERIODO2, (SELECT SUM(P3.D2_TOTAL) AS TOTAL3 FROM SD2010 P3 WITH(INDEX=SD20106) , SF4010 SF43 WHERE P.D2_COD=P3.D2_COD AND P3.D2_EMISSAO BETWEEN ´20050703´ AND ´20050703´ AND P3.D_E_L_E_T_ <> ´*´ AND P3.D2_TP IN (´PA´,´MR´) AND P3.D2_TES=SF43.F4_CODIGO AND SF43.D_E_L_E_T_ <> ´*´ AND SF43.F4_DUPLIC IN (´S´) AND SF43.F4_ESTOQUE IN (´S´,´N´) ) AS PERIODO3, (SELECT SUM(P4.D2_TOTAL) AS TOTAL4 FROM SD2010 P4 WITH(INDEX=SD20106) , SF4010 SF44 WHERE P.D2_COD=P4.D2_COD AND P4.

Ela está funcionando, mas está consumindo boa parte dos recursos do servidor sql server, tem outra maneira de criar está consulta ou é impossível ? na realidade, eu estou utilizando o tipo sub-select correlacionado.

Rogerio Amorim


Rogerio_amorim

Respostas

18/11/2005

Emerson

tente assim:

SELECT
  P.D2_COD CODIGO,
  SUM( case when P.D2_EMISSAO = ´20050701´
            then P.D2_TOTAL else 0 ) PERIODO1,
  SUM( case when P.D2_EMISSAO = ´20050702´
            then P.D2_TOTAL else 0 ) PERIODO2,
  SUM( case when P.D2_EMISSAO = ´20050703´
            then P.D2_TOTAL else 0 ) PERIODO3,
  SUM( case when P.D2_EMISSAO = ´20050704´
            then P.D2_TOTAL else 0 ) PERIODO4,
  SUM(P.D2_TOTAL) TOTALGERAL,
  SUM(P.D2_ICMSRET) TOTALICM,
  SUM(P.D2_VALIPI) TOTALIPI,
  SUM(D2_VALFRE) TOTALFRE,
  B.B1_DESC DESCRICAO
FROM
  SD2010 P WITH(INDEX=SD20106)
INNER JOIN
  SB1010 B WITH(INDEX=SB10101) ON (B.B1_COD = P.D2_COD AND B.D_E_L_E_T_ <> ´*´)
LEFT JOIN
  SF4010 SF4 ON (SF4.F4_CODIGO = P.D2_TES AND SF4.D_E_L_E_T_ <> ´*´ AND SF4.F4_DUPLIC=´S´)
WHERE
  P.D2_EMISSAO BETWEEN ´20050701´ AND ´20050704´ AND P.D_E_L_E_T_ <> ´*´
  AND P.D2_TP IN (´PA´,´MR´) AND
  AND SF4.F4_ESTOQUE<>´´
GROUP BY
  P.D2_COD, B.B1_DESC
ORDER BY
  B.B1_DESC



Responder Citar

22/11/2005

Emerson

e aí? funcionou?


Responder Citar

22/11/2005

Rogerio_amorim

Emerson, valeu pela dica !

Mas acredito que desse jeito não funcionaria pq os periodos são fixados da seguinte maneira, ex:

Periodo principal: 01/10/2005 a 31/10/2005

´1 periodo´ informado pelo usuario: 15/10/2005 (01/10/05 a 15/10/05)
´2 periodo´ informado pelo usuario: 31/10/2005 (16/10/05 a 31/10/05)

Quer dizer o usuário poderá tirar um relatorio de faturamento de uma semana ou até de um ano, mas ele está fixado em até 10 periodos. No seu exemplo ele checa se é igual a determinada data e soma, mas eu preciso que faça a soma dentro dos periodos que usuário informou seguindo o padrão acima, o que eu realmente não entendi foi o seguinte: ´SUM( case when P.D2_EMISSAO = ´20050701´
then P.D2_TOTAL else 0 ) PERIODO1,´

Vc poderia explicar melhor ???


Rogerio Amorim


Responder Citar

22/11/2005

Emerson

´SUM( case when P.D2_EMISSAO = ´20050701´
then P.D2_TOTAL else 0 ) PERIODO1,´ será utilizado para substituir os vários sub-selects que você montou. esses sub-selects é que estão sobrecarregando seu servidor.
a instrução acima diz para efetuar a soma no PERIODO1 somente se o valor de P.D2_EMISSAO for igual a ´20050701´; caso contrário acrescenta 0 (zero) à soma.

no seu caso deveria ser algo como:
SELECT 
  P.D2_COD CODIGO, 
  SUM( case when (P.D2_EMISSAO between ´20051001´ and ´20051015´)
            then P.D2_TOTAL else 0 ) PERIODO1, 
  SUM( case when (P.D2_EMISSAO between ´20051016´ and ´20051031´)
            then P.D2_TOTAL else 0 ) PERIODO2, 
  SUM(P.D2_TOTAL) TOTALGERAL, 
  SUM(P.D2_ICMSRET) TOTALICM, 
  SUM(P.D2_VALIPI) TOTALIPI, 
  SUM(D2_VALFRE) TOTALFRE, 
  B.B1_DESC DESCRICAO 
FROM 
  SD2010 P WITH(INDEX=SD20106) 
INNER JOIN 
  SB1010 B WITH(INDEX=SB10101) ON (B.B1_COD = P.D2_COD AND B.D_E_L_E_T_ <> ´*´) 
LEFT JOIN 
  SF4010 SF4 ON (SF4.F4_CODIGO = P.D2_TES AND SF4.D_E_L_E_T_ <> ´*´ AND SF4.F4_DUPLIC=´S´) 
WHERE 
  P.D2_EMISSAO BETWEEN ´20051001´ AND ´20051031´ AND P.D_E_L_E_T_ <> ´*´ 
  AND P.D2_TP IN (´PA´,´MR´) AND 
  AND SF4.F4_ESTOQUE<>´´ 
GROUP BY 
  P.D2_COD, B.B1_DESC 
ORDER BY 
  B.B1_DESC


ou seja: você monta os períodos como desejado, em função do período principal (que está no where)

p.s: você está fazendo isso para uso com o software da microsiga?


Responder Citar

22/11/2005

Rogerio_amorim

Sim, sou programador Delphi mas o sistema de ERP da empresa que trabalho atualmente, é o Protheus da Microsiga, é por isso q estou desenvolvendo em advpl. Valeu pela dica, vou dar uma checada




Rogerio Amorim


Responder Citar

22/11/2005

Rogerio_amorim

Fiz essas alterações e funcionou, só que como a query principal é um group by o campo ´d2_emissao´ precisa ser informado lá no group by por não ser um campo agregado, os registros retornam duplicados, o bom de utilizar um sub-select é que ele é totalmente independente da query principal mas veja como ficou :

SELECT 
  P.D2_COD CODIGO, 
  case when P.D2_EMISSAO between ´20051001´ and ´20051015´ 
            then SUM(P.D2_TOTAL) else 0 END PERIODO1, 
  case when P.D2_EMISSAO between ´20051016´ and ´20051031´
            then SUM(P.D2_TOTAL) else 0 END PERIODO2, 
  SUM(P.D2_TOTAL) TOTALGERAL, 
  SUM(P.D2_ICMSRET) TOTALICM, 
  SUM(P.D2_VALIPI) TOTALIPI, 
  SUM(D2_VALFRE) TOTALFRE, 
  B.B1_DESC DESCRICAO 
FROM 
  SD2010 P WITH(INDEX=SD20106) 
INNER JOIN 
  SB1010 B WITH(INDEX=SB10101) ON (B.B1_COD = P.D2_COD AND B.D_E_L_E_T_ <> ´*´) 
LEFT JOIN 
  SF4010 SF4 ON (SF4.F4_CODIGO = P.D2_TES AND SF4.D_E_L_E_T_ <> ´*´ AND SF4.F4_DUPLIC=´S´) 
WHERE 
  P.D2_EMISSAO BETWEEN ´20050101´ AND ´20051031´ AND P.D_E_L_E_T_ <> ´*´ 
  AND P.D2_TP IN (´PA´,´MR´) 
  AND SF4.F4_ESTOQUE<>´´ 
GROUP BY 
  P.D2_COD, B.B1_DESC, P.D2_EMISSAO 
ORDER BY 
  B.B1_DESC



Responder Citar