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

BlackTDN :: Posicione via SDU

SDU :: Siga Database Utility == APSDU :: Advanced Protheus “S” DataBase Utility == MPSDU :: Microsiga Protheus “S” DataBase Utility.

Quem nunca usou essa ferramenta que atire a primeira pedra.

Luizinho “Leitão” da TOTVS RJ aprendeu um cadinho de truques para usar no SDU, dentre eles: o uso da função posicione para um “Replace” via SDU.

Normalmente, quando se abre uma tabela via SDU ela recebe o seguinte “Alias” <Nome da Tabela> + “1”. Então, se abrirmos a tabela CNT010 seu alias será CNT0101.

Por padrão, não podemos abrir 2 vezes a mesma tabela. Mas nada nos impede de abrirmos duas tabelas com o mesmo nome.

Podemos abrir a tabela CNT010 via TOPCONN e a tabela CNT010 via DBFCDXADS/DBFCDXAX. Então, a primeira terá o alias CNT0101 e a segunda CNT0102.

Poderemos abrir tabelas de mesmo nome e para um mesmo RDD se estiverem ambas em localidades diferentes. Neste caso o SDU respeitará o esquema de nomeação de Alias sufixando o nome da tabela com um seqüencial 1, 2,…,n.

No exemplo, e por ser mais didático, utilizarei a tabela SX3 (Dicionário de campos do Protheus).

Vou usar duas tabelas SX3 com o mesmo nome, no mesmo RDD mais em localidades diferentes para efetuar um “Replace” (busca e substituição)  na coluna X3_ORDEM.

Em primeiro lugar vou salvar a tabela SX3010 da pasta \system\ na pasta tmp. Posso fazer isso de n maneiras. Dentre elas: copiando-a diretamente para a pasta, “Importando” (CTRL+T) ou “Copiando para (CTRL+Y) Via SDU . A vantagem de efetuar a cópia via SDU é a possibilidade efetuar um filtro.

Vamos ao exemplo:

Abrindo a tabela SX3010 via SDU usando o RDD (Driver) DBFCDXADS/DBFCDXAX.

image

image

Seleciono a ordem 1 (X3_ARQUIVO+X3_ORDEM)

image

E, agora, utilizando a opção “Copiar Para CTRL+Y” efetuo a cópia. Vou usar o mesmo Driver de Origem.

image

Observe que a sugestão de nome de arquivo segue o padrão de nomeação do Alias. Ou seja, é o nome da tabela sufixada com um número seqüencial. No nosso exemplo, como existe apenas uma tabela SX3010 aberta, o seu sufixo será “1”. Clico no botão OK e a cópia tem início. Neste caso todos os registros serão copiados pois nenhum filtro foi implementado. Vale lembrar, também, do estado de SET DELETED. Se ligado ou Desligado para a cópia, inclusive, dos registros “Deletados”.

image

Após a cópia uma mensagem com o número de registros “copiados” é mostrada conforme abaixo:

image

Considerando que a Ordem selecionada para a “Cópia” foi a 1, os registros foram fisicamente gravados na seqüencia X3_ARQUIVO + X3_ORDEM.

Agora, para que o exemplo fique mais didático, eu vou, primeiro, eliminar todos os registros da tabela SX3010 corrente (uma vez que já efetuei a cópia) utilizando a opção “ZAP CTRL+Z” para posterior “Append” na Ordem em que a cópia foi gravada.

image

Pronto. Minha tabela está limpinha e pronta para os testes.

image

Vou aproveitar a deixa e “Fechar” todos os índices da Tabela Corrente. Índice\Fechar. Isso porque, minha próxima ação será importar os registros de acordo com a Ordem de Gravação e depois efetuar o “Replace” no campo X3_ORDEM e, considerando que o campo X3_ORDEM faz parte da chave, se a mantiver aberta o processo não será concluído com sucesso.

image

Efetuando o “Append CTRL+A”:

image

Irei “Importar” os registros da tabela selecionada. No caso: a tabela anteriormente “copiada”.

image

Pronto. A tabela foi “repopulada”

.image

E, agora, usando a expressão ADVPL abaixo vou reordenar (Alterar o conteúdo do campo X3_ORDEM) de forma seqüencial e de acordo com X3_ARQUIVO de forma todos os intervalos sejam preenchidos.

IF(Type("x3o")=="C".and.xAlias==X3_ARQUIVO,x3o:=__Soma1(x3o),(xAlias:=X3_ARQUIVO,x3o:="01"))

Destrinchando a expressão ADVPL acima teremos: Usando a função condicional IF (equivalente a IIF) verifico se a variável “x30” está definida através da função Type que me retornará “C” se verdadeiro e “U” caso contrário. Se o retorno de Type() for “U” e o conteúdo de xAlias (ainda não declarada) for igual ao conteúdo da coluna/campo X3_ARQUIVO ele irá atribuir à coluna X3_ORDEM o retorno da atribuição x3o :=__Soma1(x3o), caso contrário, irá: 1 declarar (se ainda não estiver definida a variável xNome) é atribuir-lhe o conteúdo de X3_ARQUIVO e setar o conteúdo da variável x3o com “01” (valor inicial da seqüência).

Usando a opção “Replace CTRL+R”

image

(Obs.: A opção “Replace”, como todas as outras, poderiam ser melhoradas se já pré-selecionassem o campo de acordo com a coluna em foco. Normalmente a seleção  manual e a desatenção são a maior causa de problemas nesse tipo de operação).

image

image

Bem, todos os 70106 registros foram “reordenados”. Agora, ao uso da Posicione para restaurar a “Ordem” original.  Para isso, vamos, agora, “Abrir CTRL+B” a tabela SX30101 salva em \tmp\.

image

Ambas as tabelas SX3 estão abertas. Vamos prepara-las para a Posicione.

image

Mas antes, vamos descobrir qual o Alias atribuído à tabela SX30101. Para isso, basta simular uma “Cópia CTRL+Y” e o SDU nos mostrará qual Alias foi atribuído à tabela SX30101.

image

Sabemos, agora, o Alias atribuído à tabela SX30101: sx301011 (que segue a regra de atribuição anteriormente apresentada). Se a nova tabela aberta fosse SX3010 ao invés de SX30101 seu Alias seria SX30102 ao invés de SX301011. (Não precisamos confirmar a cópia e clicamos no botão “cancelar”).

Para que seja possível usar a função Posicione na tabela SX30101 ela deverá estar devidamente ordenada. Então, para isso, iremos criar um índice temporário: Índice\Criar

image

O índice será um índice temporário com as colunas X3_ARQUIVO+X3_CAMPO:

image

(Observe que para o índice ele atribui o mesmo nome do arquivo alterando, apenas, a sua extensão quando o Driver (RDD Controlador) é o DBFCDXADS/DBFCDXAX.)

image

Para o exemplo, indexamos apenas a tabela na qual a Posicione será utilizada, que é a tabela com a “Ordem Original”.

image

Agora, para que a Posicione funcione corretamente, os procedimentos abaixo deverão ser seguidos à RISCA:

  1. Selecione a Tabela na qual efetuará o “Replace CTRL+R”;
  2. Posicione o Ponteiro do Mouse na Primeira Linha da Tabela para que o “Replace” seja efetuado a partir da linha corrente;
  3. Monte a Expressão “Com” para o “Replace CTRL+R”;
    Posicione("SX301011",1,SX30101->(X3_ARQUIVO+X3_CAMPO),"X3_ORDEM")
  4. Monte a Expressão “Para” com  a “Condição do Replace”;
    (Posicione("SX301011",1,SX30101->(X3_ARQUIVO+X3_CAMPO),"X3_CAMPO")==SX30101->X3_CAMPO)

    Efetuando o “Replace”

    image

    image

    Observe que, por distração, o “Replace” foi executado na coluna/campo X3_ARQUIVO quando o correto seria na coluna X3_ORDEM. Desespero?!??!?! Não. No mínimo 2 (duas) soluções possíveis:

    image

    1. Copiar a Tabela SX30101 para SX3010 ; ou
    2. Efetuar o ZAP na Tabela SX3010, efetuar o Append dos Dados da tabela SX30101 e reordena-los ; ou
    3. Efetuar o Replace na Coluna X3_ARQUIVO de forma a restaura-la à sua situação original. (ainda bem que foi esse o campo) usando a seguinte regra:
      IF(SubStr(X3_CAMPO,3,1)=="_","S"+SubStr(X3_CAMPO,1,2),SubStr(X3_CAMPO,1,3))

      Pois a regra de formação do campo é: se o primeiro byte do Alias for “S” o campo não terá o “Alias” completo será SubStr(X3_ARQUIVO,2,2)+_+campo, caso contrário, a formação do campo será X3_ARQUIVO+_+campo.

    image

    image

    Ufa. Agora que restauramos o conteúdo do campo X3_ARQUIVO vamos ao “replace” da coluna X3_ORDEM usando Posicione.

    Mas, antes, vamos contar quantos registros foram alterados com a reordenação do campo X3_ORDEM usando a seguinte regra:

    !(Posicione("SX301011",1,SX30101->(X3_ARQUIVO+X3_CAMPO),"X3_ORDEM")==SX30101->X3_ORDEM)

    image 

    image

    image 

    e, finalmente. Restaurar a Ordem “Original”

    image

    image

    image

    Após o “Replace”, se efetuarmos a contagem anterior deveremos obter o valor 0 (Zero)

    image

    image

    Pronto. Ordem restaurada.

    ATENÇÃO :: Vale lembrar que qualquer operação efetuada diretamente no SDU deve ser feita com muita atenção e após garantir uma cópia da tabela original.

    As expressões ADVPL utilizadas no exemplo foram:

    1 - Para “Reordenar” o campo X3_ORDEM utilizando a função __Soma1()
    IF(Type("x3o")=="C".and.xAlias==X3_ARQUIVO,x3o:=__Soma1(x3o),(xAlias:=X3_ARQUIVO,x3o:="01"))
    2 - Retorno da Expressão do Replace “Com”
    Posicione("SX301011",1,SX30101->(X3_ARQUIVO+X3_CAMPO),"X3_ORDEM")
    3 - Condição do Replace “Para”
    (Posicione("SX301011",1,SX30101->(X3_ARQUIVO+X3_CAMPO),"X3_CAMPO")==SX30101->X3_CAMPO)
    4 - Restaurar o conteúdo do campo X3_ARQUIVO
    IF(SubStr(X3_CAMPO,3,1)=="_","S"+SubStr(X3_CAMPO,1,2),SubStr(X3_CAMPO,1,3))
    5 - Contar o número de registros afetados pela expressão em 1
    !(Posicione("SX301011",1,SX30101->(X3_ARQUIVO+X3_CAMPO),"X3_ORDEM")==SX30101->X3_ORDEM)

    []s
    иαldσ dj

    Comentários

    1. Preciso alterar no campo R8_DTFIM, somente o ano
      Exemplo:
      R8_DTFIM = 31/01/2014
      IF(SUBSTR(CTOD(RFQ_DTFIM,5,4)=="2014"),"2013") ISSO É POSSIVEL via APSDU?

      ResponderExcluir
    2. IF(SUBSTR(CTOD(RFQ_DTFIM,5,4)=="2014"),"2013"), e possível incluir essa função via APSDU para mudar somente o campo DATA,

      ResponderExcluir

    Postar um comentário

    Postagens mais visitadas