Array
(
)

Select com periodos independentes

Rogerio_amorim
   - 18 nov 2005

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


Emerson
   - 18 nov 2005

tente assim:

#Código

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



Emerson
   - 22 nov 2005

e aí? funcionou?


Rogerio_amorim
   - 22 nov 2005

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


Emerson
   - 22 nov 2005

´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:
#Código

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?


Rogerio_amorim
   - 22 nov 2005

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


Rogerio_amorim
   - 22 nov 2005

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 :

#Código

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