Pular para o conteúdo principal

Postagem em destaque

BlackTDN :: Como Criar Relatórios de Cotações com Dados Agrupados Usando SQL

img: DALL·E 2024-08-09 07.00.00 - A high-quality image showcasing a detailed SQL query being written in a code editor, such as VS Code, on a dark theme background. ... ## Como Criar Relatórios de Cotações com Dados Agrupados Usando SQL Quando trabalhamos com sistemas ERP e precisamos gerar relatórios de cotações que apresentam dados de múltiplos fornecedores, é comum encontrarmos a necessidade de pivotar registros que, originalmente, são apresentados de forma vertical. Isso é especialmente útil quando o objetivo é comparar preços ou condições de diferentes fornecedores para um mesmo produto em uma única linha do relatório. Neste artigo, vamos explorar uma abordagem para transformar registros verticais em colunas, facilitando a impressão de relatórios que consolidam informações de vários fornecedores em uma única linha. Vamos utilizar SQL com técnicas de pivotagem, e ao final, mostraremos como estender essa técnica para um número variável de fornecedores. ### Estrutura do Relatór

Protheus :: Advpl :: Otimizando o Filtro de Browse com @

Na dica anterior, Protheus :: Advpl :: Usando cExprFilTop Para Filtrar o Cadastro de Fornecedores de Acordo com Documento de Entrada na mBrowse, Vimos como utilizar o parâmetro cExprFilTop para criar um Filtro Relacional e, na função MATA103NFE usamos FilBrowse() para filtrar a segunda mBrowse. A questão é que FilBrowse() é, de uma certa forma lenta, e, para otimiza-la poderemos utilizar o denominado ‘Fitro “@”’ para que a expressão de filtro seja resolvida diretamente no SGBD.

Sendo assim, a expressão de filtro definida como:

cFiltra       := "F1_FORNECE+F1_LOJA$'" + SA2->( A2_COD+A2_LOJA ) + "'"

será otimizada se for reescrita e prefixada com o símbolo “@”.

cFiltra        := SA2->( "@F1_FORNECE='"+A2_COD+"' AND F1_LOJA='"+A2_LOJA+ "'" )

Na primeira forma, o filtro será avaliado registro a registro tornando-o lento, já na segunda, usamos uma expressão SQL que será resolvida diretamente pelo SGBD deixando o retorno do filtro muito, mas muito,  rápido.

A versão completa do Código com a otimização do filtro ficaria assim:

#INCLUDE "PROTHEUS.CH"
#IFDEF __TRYEXCEPTION__
    #INCLUDE "TRYEXCEPTION.CH"
#ENDIF   

/*/
    Function:    U_MATA103F
    Autor:       Marinaldo de Jesus
    Data:        18/01/2011
    Descricao:   Cadastro de Fornecedores/Doc.Entrada
    Sintaxe:     U_MATA103F
/*/
User Function MATA103F()

    Local aArea        := GetArea()
    Local aSA2Area     := SA2->( GetArea() )
    Local aSF1Area     := SF1->( GetArea() )
    Local cExprFilTop  := ""

    BEGIN SEQUENCE

   Private aRotina     := {;
                             { "Pesquisar" , "PesqBrw", 0 , 01 } ,;
                             { "Doc. de Entrada","StaticCall(U_MATA103F,MATA103NFE,'SA2',SA2->(Recno()),2)",0,02};
                          }

        Private aTela        := {}
        Private aGets        := {}

        Private cCadastro    := OemToAnsi( "Cadastro de Fornecedores vs Contratos" )
        Private bFiltraBrw   := { || .F. }

        cExprFilTop    := "A2_COD+A2_LOJA "
        cExprFilTop    += "IN "
        cExprFilTop    += "("
        cExprFilTop    += "SELECT DISTINCT "
        cExprFilTop    +=         "SA2.A2_COD+SA2.A2_LOJA "
        cExprFilTop    += "FROM "
        cExprFilTop    +=         RetSqlName( "SA2" ) + " SA2, "
        cExprFilTop    +=        RetSqlName( "SF1" ) + " SF1 "
        cExprFilTop    += "WHERE "
        cExprFilTop    +=         "SA2.D_E_L_E_T_<>'*' "
        cExprFilTop    +=    " AND "
        cExprFilTop    +=         "SF1.D_E_L_E_T_<>'*' "
        cExprFilTop    +=    " AND "
        cExprFilTop    +=         "SA2.A2_FILIAL='" + xFilial( "SA2" ) + "'"
        cExprFilTop    +=    " AND "
        cExprFilTop    +=         "SF1.F1_FILIAL='" + xFilial( "SF1" ) + "'"
        cExprFilTop    +=    " AND "
        cExprFilTop    +=         "SA2.A2_COD=SF1.F1_FORNECE "
        cExprFilTop    +=    " AND "
        cExprFilTop    +=         "SA2.A2_LOJA=SF1.F1_LOJA "
        cExprFilTop    += ")"

        MBrowse(6,1,22,75,"SA2",NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,cExprFilTop)

    END SEQUENCE

    RestArea( aSF1Area )
    RestArea( aSA2Area )
    RestArea( aArea )

Return( NIL )

/*/
    Function:    MATA103NFE
    Autor:       Marinaldo de Jesus
    Data:        18/01/2011
    Descricao:   Chamada a Rotina de Nota Fiscal de Entrada
    Sintaxe:     StaticCall(U_MATA103F,MATA103NFE,cAlias,nReg,nOpc)
/*/
Static Function MATA103NFE( cAlias , nReg , nOpc )

    Local aArea         := GetArea()
    Local aIndex        := {}
    Local aSF1Area      := SF1->( GetArea() )
    Local aModuloReSet  := SetModulo( "SIGACOM" , "COM" )
    Local bSvFilBrw     := bFiltraBrw
    Local cFiltra       := ""
    Local cSF1Alias     := "SF1"
    Local cSF1KeySeek

    Local nSF1Reg
    Local nSF1Order     := RetOrder( cSF1Alias , "F1_FILIAL+F1_FORNECE+F1_LOJA+F1_DOC" )

    Local uRet

    Private aTela       := {}
    Private aGets       := {}

    #IFDEF __TRYEXCEPTION__
        TRYEXCEPTION
    #ENDIF   

        ( cAlias )->( MsGoto( nReg ) )

        cFiltra        := SA2->( "@F1_FORNECE='"+A2_COD+"' AND F1_LOJA='"+A2_LOJA+ "'" )

        bFiltraBrw    := { || FilBrowse( "SF1" , @aIndex , @cFiltra ) }

        SF1->( dbSetOrder( nSF1Order ) )
        SF1->( Eval( bFiltraBrw ) )       

        uRet := __Execute( "MATA103()" , "xxxxxxxxxxxxxxxxxxxx" , "MATA103" , AllTrim(Str(nModulo)) , "" , 1 , .T. )

        SF1->( EndFilBrw( "SF1" , aIndex ) )

    #IFDEF __TRYEXCEPTION__

        CATCHEXCEPTION USING oException
            IF ( ValType( oException ) == "O" )
                Help( "" , 1 , ProcName() , NIL , OemToAnsi( oException:Description ) , 1 , 0 )
                ConOut( CaptureError() )
            EndIF
        ENDEXCEPTION

    #ENDIF

    bFiltraBrw    := bSvFilBrw
    SA2->( Eval( bFiltraBrw ) )

    ReSetModulo( aModuloReSet )

    RestArea( aSF1Area )
    RestArea( aArea )

Return( uRet )

Static Function __Dummy( lRecursa )
    #IFDEF __TRYEXCEPTION__
        Local oException
        TRYEXCEPTION
    #ENDIF
            DEFAULT lRecursa := .F.
            IF !( lRecursa )
                BREAK
            EndIF
            MATA103NFE()
            lRecursa := __Dummy( .F. )
    #IFDEF __TRYEXCEPTION__
        CATCHEXCEPTION USING oException
        ENDEXCEPTION
    #ENDIF  
Return( lRecursa )

Procure, sempre que possível utilizar o filtro “@” em suas consultas da mBrowse ou na chamada a Funções de Filtro, como por exemplo, a FilBrowse().

Para baixar , o novo e otimizado exemplo, clique aqui

[]s

иαldσ dj

Comentários

  1. Fala naldo, bão cara?

    Esse caso da imagem em uma tabela SXB de consultas padrao se refere ao mesmo caso.
    https://lh4.googleusercontent.com/-6Id7qI8cC1k/Toxg9OSTn9I/AAAAAAAAAjY/nc28dqPINkE/s800/filtro%252520na%252520consulta%252520padrao.jpg

    Isso caracteriza filtro de otimizacao via SQL?

    Vlw

    ResponderExcluir
  2. Isso mesmo Sérgio... Os Filtros das Consultas Padrões (SXB) também podem ser beneficiadas com o "Filtro @" de forma a "otimizar" o processo de montagem da consulta. O espaço aqui é pequeno para explanar sobre o assunto que merece um "post".

    []s

    иαldσ dj

    ResponderExcluir
  3. Naldo, boa tarde,

    Cara vc já usou o essa rotina __Execute no Protheus11? Aqui da um erro na lib muito bizarro...

    Eu criei uma outra rotina chamando somente essa função e estourou o mesmo erro, sabe se existe alguma coisa a ser feita antes de chamar esta função?

    Segue erro:

    THREAD ERROR (rodrigo, STO-IPD-N10) 18/10/2012 14:52:59
    invalid property OMSGBAR on BEGINFLATMODE(APLIB000.PRW) 27/02/2012 16:36:07 line : 1347

    [TOTVS build: 7.00.111010P-20120120]
    Called from __EXECUTE(APLIB090.PRW) 10/07/2012 17:12:06 line : 214
    Called from U_MATA103F(U_MATA103F.PRG) 18/10/2012 14:51:11 line : 33
    Called from SIGAIXB(APLIB190.PRW) 14/12/2011 18:31:10 line : 226
    Called from __EXECUTE(APLIB090.PRW) 10/07/2012 17:12:06 line : 487
    Called from FWPREEXECUTE(FWPREEXECUTE.PRW) 17/08/2011 18:06:36 line : 65
    Called from {|| FWPreExecute('Fornecedor / Doc. Entrada', 'MATA103F()', 3, '02', 'xxxxxxxxxx') } line : 247
    Called from ::TWINDOW:ACTIVATE
    Called from MSAPP:ACTIVATE(FWAPP.PRW) 17/07/2012 16:33:17 line : 519
    Called from SIGAADV(APLIB000.PRW) 27/02/2012 16:36:07 line : 54

    ResponderExcluir
  4. Naldo, boa tarde,

    Cara vc já usou o essa rotina __Execute no Protheus11? Aqui da um erro na lib muito bizarro...

    Eu criei uma outra rotina chamando somente essa função e estourou o mesmo erro, sabe se existe alguma coisa a ser feita antes de chamar esta função?

    Segue erro:

    THREAD ERROR (rodrigo, STO-IPD-N10) 18/10/2012 14:52:59
    invalid property OMSGBAR on BEGINFLATMODE(APLIB000.PRW) 27/02/2012 16:36:07 line : 1347

    [TOTVS build: 7.00.111010P-20120120]
    Called from __EXECUTE(APLIB090.PRW) 10/07/2012 17:12:06 line : 214
    Called from U_MATA103F(U_MATA103F.PRG) 18/10/2012 14:51:11 line : 33
    Called from SIGAIXB(APLIB190.PRW) 14/12/2011 18:31:10 line : 226
    Called from __EXECUTE(APLIB090.PRW) 10/07/2012 17:12:06 line : 487
    Called from FWPREEXECUTE(FWPREEXECUTE.PRW) 17/08/2011 18:06:36 line : 65
    Called from {|| FWPreExecute('Fornecedor / Doc. Entrada', 'MATA103F()', 3, '02', 'xxxxxxxxxx') } line : 247
    Called from ::TWINDOW:ACTIVATE
    Called from MSAPP:ACTIVATE(FWAPP.PRW) 17/07/2012 16:33:17 line : 519
    Called from SIGAADV(APLIB000.PRW) 27/02/2012 16:36:07 line : 54

    ResponderExcluir
    Respostas
    1. Vou ser se consigo reproduzir o erro e publico a solução.

      Excluir
    2. Bom Dia.

      Fiz uma customização e me ocorreu o mesmo erro mostrado no comentario acima do RSGomes.

      Alguem sabe como resolver?

      Desde já agradeço a ajuda.

      Jefferson Moreira

      Excluir
    3. Bom Dia.

      Fiz uma customização e me ocorreu o mesmo erro mostrado no comentario acima do RSGomes.

      Alguem sabe como resolver?

      Desde já agradeço a ajuda.

      Jefferson Moreira

      Excluir
  5. Boa tarde...

    Consegui rodar a rotina aqui!!!!! O bizarro foi como... Eu simplesmente mudei o tema do Protheus 11 do Standard para o Clássico...

    Agora o que eu não consegui foi utilizar o "@" para filtra o SF1. Na verdade o SF1 até é filtrado (verifiquei debugando a rotina antes da chamada da função MATA103). Mas quando o MATA103 é executado os registro não aparecem filtrados.

    De qualquer forma não é um problema já que a performance do filtro sem o "@" está muito bom aqui.

    P.S.: Detalhe: Quando o tema estava no Standard o filtro sem o "@" ficou extremamente lento... Vai entender...

    Abraços

    ResponderExcluir
  6. Boa tarde Naldo,

    Sou novo por aqui(BlackTdn), mas um curioso na programação em ADVPL há mais de 5 anos.
    Estou desenvolvendo um software de TimeSheet pra executar todo em Prepare Environment. Estou na versão 10 do Protheus e gostaria de saber se já conseguiu criar uma tela modelo 2 em tela cheia, por exemplo chamada via Mbrowse.

    Detalhe: Estou executando via Prepare Environment, comando __Execute

    Agradeço a atenção.

    Bruno Abrigo

    ResponderExcluir
    Respostas
    1. Bruno,

      Isso que você está querendo fazer é bem simples, observe os parâmetros da Modelo2.

      Modelo2(cTitulo,aC,aR,aCGD,nOpcx,cLineOk,cAllOk,aGetsGD,bF4,cIniCpos,nMax,aCordW,lDelGetD,lMaximized, aButtons)


      Dentre eles aCordW e lMaximized irão resolver o seu problema.

      aCordW -> espera as coordenadas da janela que poderão ser obtidas com MsAdvSize()
      lMaximized -> Com .T. fará com que o Dialog seja montado de forma Maximizaa.

      No seu caso aCordW ficaria como

      aCordW := MsAdvSize( NIL , .F. )
      e
      lMaximized := .T.

      []s
      Naldo

      Excluir
    2. "Bruno Abrigo
      2:36 PM (9 minutes ago)

      to me
      Pow Naldo!
      Que legal falar com vc, tú é real mermo! Rs

      Cara veja como estou preenchendo os parâmetros:

      aR:={}
      aCGD := {44,5,118,315}
      aCordW := MsAdvSize( NIL , .F. )
      lRetMod2:=Modelo2(cTitulo,aC,aR,aCGD,nOpcx,cLinhaOk,cTudoOk,aGetSD, ,, , aCordW ,,.T.)//GetmBrowse())

      Ainda não consegui abrir em tela inteira. O que esta falantando?

      Vlww!"

      Resposta:

      Bruno,

      Falha minha. as Coordenadas de aCordW não são equivalentes as retornadas pela MsAdvSize() então o seguinte ajuste se faz necessário:

      aAdvSize := MsAdvSize( NIL ,.F. )
      aCordW := Array(Len(aAdvSize))

      aCordW[1] := aAdvSize[7]
      aCordW[2] := 0
      aCordW[3] := aAdvSize[6]
      aCordW[4] := aAdvSize[5]

      []s
      Naldo

      Excluir
    3. Ou, para manter aCordW com o Tamanho Esprado:

      aAdvSize := MsAdvSize( NIL ,.F. )
      aCordW := Array(4)

      aCordW[1] := aAdvSize[7]
      aCordW[2] := 0
      aCordW[3] := aAdvSize[6]
      aCordW[4] := aAdvSize[5]

      []s
      Naldo

      Read more: http://www.blacktdn.com.br/2011/09/protheus-advpl-otimizando-o-filtro-de.html#ixzz2VMhoq9fn

      Excluir
    4. Bruno Abrigo
      3:06 PM (12 minutes ago)

      to me
      Valeu naldo, fiz alguns acertos pra chegar no meu objetivo mas era essa ajuda que eu precisava.

      Parabéns!

      Bruno

      Excluir

Postar um comentário

Postagens mais visitadas