Profissionais que trabalham com o ERP Protheus sabem que a análise completa de um processo, como o de Compras, pode ser desafiadora. Frequentemente, precisamos cruzar informações de diversas tabelas (SC1
, SC7
, SD1
, SA2
, SBM
, SDE
, etc.) para ter uma visão 360 graus. Estou trabalhando atualmente em um relatório desse tipo e achei que seria interessante falar sobre esse desafio comum que surge ao tentar mapear o fluxo completo do processo de Compras no Protheus desde a Solicitação de Compra (SC1) até a Nota Fiscal de Entrada (SD1). A abordagem padrão com LEFT JOIN
partindo da SC1 funciona bem para documentos vinculados, mas o que acontece com:
Pedidos de Compra (SC7) que foram gerados sem uma Solicitação de Compra?
Itens de Nota Fiscal (SD1) que foram lançados sem um Pedido de Compra associado?
Esses documentos "órfãos" não aparecem em relatórios que partem apenas da SC1. Para ter uma análise verdadeiramente completa, precisamos incluir esses cenários. É aqui que o poderoso operador UNION ALL
do SQL se torna nosso grande aliado.
Claro, geralmente esses casos não fazem parte do "processo de negócio" padrão, mas sabemos que muitas situações no dia a dia do negócio fogem dos procedimentos convencionais e, no final das contas, é ao departamente de TI que recorrem para tentar colocar alguma ordem no Caos e conseguir visibilidade sobre as informações que o sistema armazena.
Este post é para você, analista de negócios, programador ADVPL ou profissional de TI que busca ir além na análise de dados do Protheus. Vamos explorar como usar o UNION ALL
para criar uma query que combine dados de Solicitações, Pedidos sem Solicitação e Notas sem Pedido em um único resultado.
O Desafio do LEFT JOIN
Partindo da SC1
Sua query original, como muitas, provavelmente começa selecionando da tabela de Solicitações de Compra (SC1
) e usando LEFT JOIN
para trazer informações de Pedidos (SC7
) e Notas (SD1
) quando elas existem:
FROM SC1120 SC1
LEFT JOIN SC7120 SC7 ON SC7.C7_NUMSC = SC1.C1_NUM AND ...LEFT JOIN SD1120 SD1 ON SD1.D1_PEDIDO = SC7.C7_NUM AND ...
Essa estrutura é excelente para ver o que aconteceu a partir de uma Solicitação. Mas se um Pedido (SC7
) foi incluído diretamente, sem preencher os campos C7_NUMSC
e C7_ITEMSC
, ele simplesmente não será encontrado ao partir da SC1
. Da mesma forma, uma Nota Fiscal (SD1
) lançada sem um Pedido associado (campos D1_PEDIDO
e D1_ITEMPC
vazios) não aparecerá se a busca depender da ligação com SC7
.
A Solução: Combinando Cenários com UNION ALL
Para resolver isso, podemos construir a análise em torno das três possíveis "chaves" principais que você deseja visualizar:
Registros que possuem uma Solicitação de Compra (SC1).
Registros que possuem um Pedido de Compra (SC7), mas não uma Solicitação de Compra (SC1).
Registros que possuem um Item de Nota Fiscal (SD1), mas não um Pedido de Compra (SC7).
O UNION ALL
nos permite executar uma query para cada um desses cenários e combinar todos os resultados em uma única lista.
Regra Crucial do UNION ALL
: Todas as queries que você unir devem retornar o mesmo número de colunas, na mesma ordem, com os mesmos nomes (aliases) e tipos de dados compatíveis. Onde um campo não existe para um determinado cenário, você deve selecionar NULL
ou um valor padrão compatível.
Construindo a Query Combinada
Vamos usar a query final que discutimos como exemplo. Ela é dividida em três partes (SELECT
s), unidas por UNION ALL
.
Observação Importante sobre Protheus e SQL: Em sistemas como o Protheus, campos de chave estrangeira que não possuem um vínculo correspondente frequentemente são preenchidos com espaços em branco em vez de NULL
s verdadeiros. Nossas condições WHERE
precisarão levar isso em conta.
Aqui está um exemplo dessa query:
-- Consulta combinada para obter SC1, SC7 sem SC1, e SD1 sem SC7 -- Os resultados são unidos usando UNION ALL. -- Cada SELECT deve ter o mesmo número, ordem e tipo de colunas. -- BRANCH 1: Registros que possuem SC1 como base (similar à sua query original) SELECT 'SC' AS TIPO_REGISTRO, -- Subquery para APROVADOR (depende de SC7) (SELECT CR_USER FROM SCR120 CRSUB2 WHERE CR_NIVEL = (SELECT MAX(CR_NIVEL) FROM SCR120 CRSUB WHERE (SC7.C7_CONAPRO = 'L' OR SC7.C7_CONAPRO IS NULL) -- Adicionado IS NULL check para garantir que a subquery não quebre se SC7 for NULL AND CRSUB.CR_NUM = SC7.C7_NUM AND CRSUB.D_E_L_E_T_ = ' ' AND CRSUB.CR_STATUS = '03' AND CRSUB.CR_FILIAL = SC7.C7_FILIAL) AND CRSUB2.CR_STATUS = '03' AND CRSUB2.CR_NUM = SC7.C7_NUM AND CRSUB2.CR_FILIAL = SC7.C7_FILIAL AND CRSUB2.D_E_L_E_T_ = ' ') AS APROVADOR, -- Subquery para DATA_APROV (depende de SC7) (SELECT CR_DATALIB FROM SCR120 CRSUB2 WHERE CR_NIVEL = (SELECT MAX(CR_NIVEL) FROM SCR120 CRSUB WHERE (SC7.C7_CONAPRO = 'L' OR SC7.C7_CONAPRO IS NULL) -- Adicionado IS NULL check AND CRSUB.CR_NUM = SC7.C7_NUM AND CRSUB.D_E_L_E_T_ = ' ' AND CRSUB.CR_STATUS = '03' AND CRSUB.CR_FILIAL = SC7.C7_FILIAL) AND CRSUB2.CR_STATUS = '03' AND CRSUB2.CR_NUM = SC7.C7_NUM AND CRSUB2.CR_FILIAL = SC7.C7_FILIAL AND CRSUB2.D_E_L_E_T_ = ' ') AS DATA_APROV, SC1.C1_FILIAL, SC7.C7_FILIAL, SD1.D1_FILIAL, SC1.C1_NUM, SC1.C1_ITEM, SC7.C7_NUM, SC7.C7_ITEM, SC7.C7_NUMSC, SC7.C7_ITEMSC, SC7.C7_EMISSAO, SC7.C7_FORNECE, SC7.C7_LOJA, SA2.A2_NOME, SD1.D1_DOC, SD1.D1_DTDIGIT, SD1.D1_SERIE, SD1.D1_FORNECE, SD1.D1_LOJA, SC7.C7_RESIDUO, SB1.B1_GRUPO, SBM.BM_DESC, SC1.C1_PRODUTO, SC1.C1_DESCRI, SB1.B1_ESPECIF, SC1.C1_UM, SC1.C1_SEGUM, SC1.C1_EMISSAO, SC1.C1_PEDIDO, SC1.C1_ITEMPED, SC1.C1_SOLICIT, SC1.C1_QUJE, SC1.C1_QUANT, SC7.C7_QUANT, SC7.C7_PRECO, SC7.C7_TOTAL, SD1.D1_VUNIT, SD1.D1_TOTAL, SC7.C7_CC, SC7.C7_ITEMCTA, SC7.C7_CONTA, SD1.D1_CC, SD1.D1_ITEMCTA, SD1.D1_CONTA, SC7.C7_TIPO, CASE WHEN SC7.C7_RATEIO = '1' THEN 'SIM' WHEN SC7.C7_RATEIO = '2' THEN 'NAO' ELSE SC7.C7_RATEIO END AS C7_RATEIO, CASE WHEN SD1.D1_RATEIO = '1' THEN 'SIM' WHEN SD1.D1_RATEIO = '2' THEN 'NAO' ELSE SD1.D1_RATEIO END AS D1_RATEIO, -- Selecionando D1_VUNIT e D1_TOTAL novamente com aliases distintos para consistência com a lista original SD1.D1_VUNIT AS D1_VUNIT_SEL, SD1.D1_TOTAL AS D1_TOTAL_SEL, SDE.DE_CC, SDE.DE_CONTA, SDE.DE_DOC, SDE.DE_FILIAL, SDE.DE_PERC, SDE.DE_FORNECE, SDE.DE_LOJA, -- Primeira menção de DE_LOJA SDE.DE_ITEM, SDE.DE_ITEMCTA, SDE.DE_ITEMNF, SDE.DE_LOJA AS DE_LOJA_ALIAS, -- Segunda menção de DE_LOJA com alias SDE.DE_SERIE, (SD1.D1_VUNIT * (SDE.DE_PERC/100)) AS VAL_UNIT_RAT, (SD1.D1_TOTAL * (SDE.DE_PERC/100)) AS VAL_TOT_RAT, CASE WHEN SC7.C7_CONAPRO = 'B' THEN 'Ñ APROVADO' WHEN SC7.C7_CONAPRO = 'L' THEN 'APROVADO' WHEN SC7.C7_CONAPRO = 'R' THEN 'ELIMINADO POR RESIDUO' ELSE SC7.C7_CONAPRO END AS C7_CONAPRO, -- Adicionado ELSE SC1.C1_SOLICIT AS C1_SOLICIT_SEL, -- C1_SOLICIT selecionado uma vez com alias SC1.C1_OBS, SC7.C7_OBS, SC1.C1_EMISSAO, SC7.C7_EMISSAO, SD1.D1_EMISSAO, SC1.C1_DTAPRO FROM SC1120 SC1 LEFT JOIN SB1010 SB1 ON SB1.B1_COD = SC1.C1_PRODUTO AND SB1.D_E_L_E_T_ = ' ' LEFT JOIN SBM010 SBM ON SBM.BM_GRUPO = SB1.B1_GRUPO AND SBM.D_E_L_E_T_ = ' ' LEFT JOIN SC7120 SC7 ON SC7.C7_NUMSC = SC1.C1_NUM AND SC7.C7_ITEMSC = SC1.C1_ITEM AND SC7.C7_FILIAL = SC1.C1_FILIAL AND SC7.D_E_L_E_T_ = ' ' LEFT JOIN SA2120 SA2 ON SA2.A2_COD = SC7.C7_FORNECE AND SA2.A2_LOJA = SC7.C7_LOJA AND SA2.D_E_L_E_T_ = ' ' LEFT JOIN SD1120 SD1 ON SD1.D1_PEDIDO = SC7.C7_NUM AND SD1.D1_ITEMPC = SC7.C7_ITEM AND SD1.D1_FILIAL = SC7.C7_FILIAL AND SD1.D_E_L_E_T_ = ' ' LEFT JOIN SDE120 SDE ON SDE.DE_DOC = SD1.D1_DOC AND SDE.DE_SERIE = SD1.D1_SERIE AND SDE.DE_FILIAL = SD1.D1_FILIAL AND SDE.DE_FORNECE = SD1.D1_FORNECE AND SDE.DE_LOJA = SD1.D1_LOJA AND SDE.DE_ITEMNF = SD1.D1_ITEM AND SDE.D_E_L_E_T_ = ' ' WHERE SC1.D_E_L_E_T_ = ' ' AND SC1.C1_FILIAL >= ' ' AND SC1.C1_FILIAL <= 'ZZ' AND SC1.C1_EMISSAO >= '20250201' AND SC1.C1_EMISSAO <= '20250424' AND SC1.C1_NUM >= ' ' AND SC1.C1_NUM <= '999999' AND SC1.C1_PRODUTO >= ' ' AND SC1.C1_PRODUTO <= 'ZZZZZZZZZZZZZZZ' AND SC1.C1_ITEMCTA >= ' ' AND SC1.C1_ITEMCTA <= 'ZZZZZZZZZ' AND SC1.C1_CC >= ' ' AND SC1.C1_CC <= 'ZZZZZZZZZ' AND SC7.C7_TIPO <> 3 -- Aplica filtro C7_TIPO apenas se SC7 existir UNION ALL -- BRANCH 2: Registros que possuem SC7 como base, mas NÃO possuem SC1 correspondente SELECT 'PC/AE' AS TIPO_REGISTRO, -- Subquery para APROVADOR (depende de SC7) (SELECT CR_USER FROM SCR120 CRSUB2 WHERE CR_NIVEL = (SELECT MAX(CR_NIVEL) FROM SCR120 CRSUB WHERE SC7.C7_CONAPRO = 'L' -- SC7 é a base, então C7_CONAPRO não será NULL aqui AND CRSUB.CR_NUM = SC7.C7_NUM AND CRSUB.D_E_L_E_T_ = ' ' AND CRSUB.CR_STATUS = '03' AND CRSUB.CR_FILIAL = SC7.C7_FILIAL) AND CRSUB2.CR_STATUS = '03' AND CRSUB2.CR_NUM = SC7.C7_NUM AND CRSUB2.CR_FILIAL = SC7.C7_FILIAL AND CRSUB2.D_E_L_E_T_ = ' ') AS APROVADOR, -- Subquery para DATA_APROV (depende de SC7) (SELECT CR_DATALIB FROM SCR120 CRSUB2 WHERE CR_NIVEL = (SELECT MAX(CR_NIVEL) FROM SCR120 CRSUB WHERE SC7.C7_CONAPRO = 'L' -- SC7 é a base AND CRSUB.CR_NUM = SC7.C7_NUM AND CRSUB.D_E_L_E_T_ = ' ' AND CRSUB.CR_STATUS = '03' AND CRSUB.CR_FILIAL = SC7.C7_FILIAL) AND CRSUB2.CR_STATUS = '03' AND CRSUB2.CR_NUM = SC7.C7_NUM AND CRSUB2.CR_FILIAL = SC7.C7_FILIAL AND CRSUB2.D_E_L_E_T_ = ' ') AS DATA_APROV, NULL AS C1_FILIAL, SC7.C7_FILIAL, SD1.D1_FILIAL, -- C1_FILIAL é NULL NULL AS C1_NUM, NULL AS C1_ITEM, -- C1 campos são NULL SC7.C7_NUM, SC7.C7_ITEM, SC7.C7_NUMSC, SC7.C7_ITEMSC, SC7.C7_EMISSAO, SC7.C7_FORNECE, SC7.C7_LOJA, SA2.A2_NOME, SD1.D1_DOC, SD1.D1_DTDIGIT, SD1.D1_SERIE, SD1.D1_FORNECE, SD1.D1_LOJA, SC7.C7_RESIDUO, NULL AS B1_GRUPO, NULL AS BM_DESC, -- SB1/SBM são NULL (ligados via SC1) NULL AS C1_PRODUTO, NULL AS C1_DESCRI, NULL AS B1_ESPECIF, NULL AS C1_UM, NULL AS C1_SEGUM, NULL AS C1_EMISSAO, NULL AS C1_PEDIDO, NULL AS C1_ITEMPED, NULL AS C1_SOLICIT, NULL AS C1_QUJE, NULL AS C1_QUANT, -- C1/SB1 campos são NULL SC7.C7_QUANT, SC7.C7_PRECO, SC7.C7_TOTAL, SD1.D1_VUNIT, SD1.D1_TOTAL, SC7.C7_CC, SC7.C7_ITEMCTA, SC7.C7_CONTA, SD1.D1_CC, SD1.D1_ITEMCTA, SD1.D1_CONTA, SC7.C7_TIPO, CASE WHEN SC7.C7_RATEIO = '1' THEN 'SIM' WHEN SC7.C7_RATEIO = '2' THEN 'NAO' ELSE SC7.C7_RATEIO END AS C7_RATEIO, CASE WHEN SD1.D1_RATEIO = '1' THEN 'SIM' WHEN SD1.D1_RATEIO = '2' THEN 'NAO' ELSE SD1.D1_RATEIO END AS D1_RATEIO, SD1.D1_VUNIT AS D1_VUNIT_SEL, SD1.D1_TOTAL AS D1_TOTAL_SEL, SDE.DE_CC, SDE.DE_CONTA, SDE.DE_DOC, SDE.DE_FILIAL, SDE.DE_PERC, SDE.DE_FORNECE, SDE.DE_LOJA, -- Primeira menção de DE_LOJA SDE.DE_ITEM, SDE.DE_ITEMCTA, SDE.DE_ITEMNF, SDE.DE_LOJA AS DE_LOJA_ALIAS, -- Segunda menção de DE_LOJA com alias SDE.DE_SERIE, (SD1.D1_VUNIT * (SDE.DE_PERC/100)) AS VAL_UNIT_RAT, (SD1.D1_TOTAL * (SDE.DE_PERC/100)) AS VAL_TOT_RAT, CASE WHEN SC7.C7_CONAPRO = 'B' THEN 'Ñ APROVADO' WHEN SC7.C7_CONAPRO = 'L' THEN 'APROVADO' WHEN SC7.C7_CONAPRO = 'R' THEN 'ELIMINADO POR RESIDUO' ELSE SC7.C7_CONAPRO END AS C7_CONAPRO, -- Adicionado ELSE NULL AS C1_SOLICIT_SEL, -- C1_SOLICIT é NULL NULL AS C1_OBS, SC7.C7_OBS, -- C1_OBS é NULL NULL AS C1_EMISSAO, SC7.C7_EMISSAO, SD1.D1_EMISSAO, NULL AS C1_DTAPRO -- C1 datas são NULL FROM SC7120 SC7 LEFT JOIN SA2120 SA2 ON SA2.A2_COD = SC7.C7_FORNECE AND SA2.A2_LOJA = SC7.C7_LOJA AND SA2.D_E_L_E_T_ = ' ' LEFT JOIN SD1120 SD1 ON SD1.D1_PEDIDO = SC7.C7_NUM AND SD1.D1_ITEMPC = SC7.C7_ITEM AND SD1.D1_FILIAL = SC7.C7_FILIAL AND SD1.D_E_L_E_T_ = ' ' LEFT JOIN SDE120 SDE ON SDE.DE_DOC = SD1.D1_DOC AND SDE.DE_SERIE = SD1.D1_SERIE AND SDE.DE_FILIAL = SD1.D1_FILIAL AND SDE.DE_FORNECE = SD1.D1_FORNECE AND SDE.DE_LOJA = SD1.D1_LOJA AND SDE.DE_ITEMNF = SD1.D1_ITEM AND SDE.D_E_L_E_T_ = ' ' WHERE SC7.D_E_L_E_T_ = ' ' AND SC7.C7_NUMSC = ' ' -- ESSENCIAL: Garante que NÃO há vínculo com SC1 AND SC7.C7_ITEMSC = ' ' -- ESSENCIAL: Garante que NÃO há vínculo com SC1 AND SC7.C7_FILIAL >= ' ' AND SC7.C7_FILIAL <= 'ZZ' -- Filtro de filial na base AND SC7.C7_EMISSAO >= '20250201' AND SC7.C7_EMISSAO <= '20250424' -- Filtro de data na base AND SC7.C7_NUM >= ' ' AND SC7.C7_NUM <= '999999' -- Filtro de número na base AND SC7.C7_TIPO <> 3 UNION ALL -- BRANCH 3: Registros que possuem SD1 como base, mas NÃO possuem SC7 correspondente SELECT 'NF' AS TIPO_REGISTRO, NULL AS APROVADOR, -- SC7 não existe, então NULL NULL AS DATA_APROV, -- SC7 não existe, então NULL NULL AS C1_FILIAL, NULL AS C7_FILIAL, SD1.D1_FILIAL, -- C1 e C7 filiais são NULL NULL AS C1_NUM, NULL AS C1_ITEM, -- C1 campos são NULL NULL AS C7_NUM, NULL AS C7_ITEM, NULL AS C7_NUMSC, NULL AS C7_ITEMSC, NULL AS C7_EMISSAO, NULL AS C7_FORNECE, NULL AS C7_LOJA, NULL AS A2_NOME, -- C7 e SA2 não existem, então NULL SD1.D1_DOC, SD1.D1_DTDIGIT, SD1.D1_SERIE, SD1.D1_FORNECE, SD1.D1_LOJA, NULL AS C7_RESIDUO, -- SC7 não existe, então NULL NULL AS B1_GRUPO, NULL AS BM_DESC, -- SB1/SBM não existem (ligados via SC1) NULL AS C1_PRODUTO, NULL AS C1_DESCRI, NULL AS B1_ESPECIF, NULL AS C1_UM, NULL AS C1_SEGUM, NULL AS C1_EMISSAO, NULL AS C1_PEDIDO, NULL AS C1_ITEMPED, NULL AS C1_SOLICIT, NULL AS C1_QUJE, NULL AS C1_QUANT, -- C1/SB1 campos são NULL NULL AS C7_QUANT, NULL AS C7_PRECO, NULL AS C7_TOTAL, -- SC7 não existe, então NULL SD1.D1_VUNIT, SD1.D1_TOTAL, NULL AS C7_CC, NULL AS C7_ITEMCTA, NULL AS C7_CONTA, -- C7 campos são NULL SD1.D1_CC, SD1.D1_ITEMCTA, SD1.D1_CONTA, NULL AS C7_TIPO, -- SC7 não existe, então NULL NULL AS C7_RATEIO, -- SC7 não existe, então NULL CASE WHEN SD1.D1_RATEIO = '1' THEN 'SIM' WHEN SD1.D1_RATEIO = '2' THEN 'NAO' ELSE SD1.D1_RATEIO END AS D1_RATEIO, SD1.D1_VUNIT AS D1_VUNIT_SEL, SD1.D1_TOTAL AS D1_TOTAL_SEL, SDE.DE_CC, SDE.DE_CONTA, SDE.DE_DOC, SDE.DE_FILIAL, SDE.DE_PERC, SDE.DE_FORNECE, SDE.DE_LOJA, -- Primeira menção de DE_LOJA SDE.DE_ITEM, SDE.DE_ITEMCTA, SDE.DE_ITEMNF, SDE.DE_LOJA AS DE_LOJA_ALIAS, -- Segunda menção de DE_LOJA com alias SDE.DE_SERIE, (SD1.D1_VUNIT * (SDE.DE_PERC/100)) AS VAL_UNIT_RAT, (SD1.D1_TOTAL * (SDE.DE_PERC/100)) AS VAL_TOT_RAT, NULL AS C7_CONAPRO, -- SC7 não existe, então NULL NULL AS C1_SOLICIT_SEL, -- C1_SOLICIT é NULL NULL AS C1_OBS, NULL AS C7_OBS, -- C1 e C7 OBS são NULL NULL AS C1_EMISSAO, NULL AS C7_EMISSAO, SD1.D1_EMISSAO, NULL AS C1_DTAPRO -- C1 e C7 datas são NULL FROM SD1120 SD1 LEFT JOIN SDE120 SDE ON SDE.DE_DOC = SD1.D1_DOC AND SDE.DE_SERIE = SD1.D1_SERIE AND SDE.DE_FILIAL = SD1.D1_FILIAL AND SDE.DE_FORNECE = SD1.D1_FORNECE AND SDE.DE_LOJA = SD1.D1_LOJA AND SDE.DE_ITEMNF = SD1.D1_ITEM AND SDE.D_E_L_E_T_ = ' ' WHERE SD1.D_E_L_E_T_ = ' ' AND SD1.D1_PEDIDO = ' ' -- ESSENCIAL: Garante que NÃO há vínculo com SC7 AND SD1.D1_ITEMPC = ' ' -- ESSENCIAL: Garante que NÃO há vínculo com SC7 AND SD1.D1_FILIAL >= ' ' AND SD1.D1_FILIAL <= 'ZZ' -- Filtro de filial na base AND SD1.D1_DTDIGIT >= '20250201' AND SD1.D1_DTDIGIT <= '20250424' -- Filtro de data na base
Detalhes Importantes:
TIPO_REGISTRO
: Adicionamos uma coluna literal em cadaSELECT
para identificar facilmente a origem da linha ('SC'
,'PC/AE'
,'NF'
). Isso é crucial para a análise visual ou para processamento posterior (ex: em um relatório ADVPL).Condições
WHERE
para "Sem Pai": As cláusulasWHERE
nos branches 2 e 3 são a chave. Elas filtram os registros da tabela base (SC7
ouSD1
) que não têm os campos de ligação preenchidos. A verificação(CAMPO IS NULL OR TRIM(CAMPO) = '')
é robusta para lidar comNULL
s e strings de espaços.Filtros de Filial e Data: Os filtros na filial e data devem ser aplicados à tabela que é a base de cada branch (
SC1
no Branch 1,SC7
no Branch 2,SD1
no Branch 3).
Aplicando em Relatórios ADVPL
Ao usar essa query em um relatório customizado ADVPL, você executará a query combinada e iterará sobre o resultado. A coluna TIPO_REGISTRO
permitirá que você trate cada linha de forma diferente, exibindo as informações relevantes para SC, PC/AE ou NF, mesmo que muitos campos estejam NULL
para determinados tipos de registro.
Por exemplo, no seu código ADVPL, ao ler uma linha da query, você pode usar um IF
ou CASE
baseado no valor da coluna TIPO_REGISTRO
para determinar quais campos exibir ou como formatar a saída.
Conclusão
O UNION ALL
é uma ferramenta poderosa para análise de dados em sistemas complexos como o Protheus. Ao quebrar seu problema em sub-problemas (os diferentes cenários de documentos) e combiná-los, você obtém uma visão completa e precisa do processo de Compras, identificando não apenas o fluxo padrão, mas também os documentos que existem fora dele.
Dominar essa técnica é um passo importante para qualquer profissional que busca extrair o máximo de informação do ERP Protheus e criar relatórios customizados eficientes em ADVPL.
Experimente a query e adapte os filtros de data e filial conforme a sua necessidade para obter a análise desejada!
Comentários
Postar um comentário