ETL de banco externo pro Protheus
Como importar dados de SQL externo (legacy, CRM, ERP antigo) pro Protheus com transformacao. Padrao Extract-Transform-Load aplicado.
Migracao de sistema legado, integracao com CRM, sincronizacao com filial remota — tudo cai em ETL. Esse e o padrao tecnico pra trazer dados de fora pro Protheus de forma segura.
Fluxo classico ETL
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ Source │ ──→ │ Extract │ ──→ │ Transform │ ──→ │ Load │
│ (SQL ext) │ │ (TCQuery) │ │ (mapping) │ │ (Protheus) │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
Extract: conectar no banco externo
// TCLink permite conectar em outro banco
nConn := TCLink("MyDriverODBC", "external_db", "user", "pass")
If nConn < 0
ConOut("Erro de conexao: " + cValToChar(TCSqlError()))
Return
EndIf
TCSetConn(nConn)
cQry := "SELECT * FROM clientes_legado WHERE migrado = 0"
TCQuery cQry New Alias "LEGACY"
// Volta pra conexao padrao Protheus depois
TCSetConn(0)
Transform: mapping de campos
Static Function MapearCliente(oLegacy)
Local aCab := {}
// Codigo: gerar novo seguindo padrao SX8
Local cCodigo := GetSXENum("SA1", "A1_COD")
aAdd(aCab, {"A1_FILIAL", xFilial("SA1"), NIL})
aAdd(aCab, {"A1_COD", cCodigo, NIL})
aAdd(aCab, {"A1_LOJA", "01", NIL})
aAdd(aCab, {"A1_NOME", AllTrim(oLegacy["nome"]), NIL})
// Transform: legado tinha "PJ"/"PF", aqui e "J"/"F"
aAdd(aCab, {"A1_PESSOA", If(oLegacy["tipo"] == "PJ", "J", "F"), NIL})
// Padronizar CNPJ — remover formatacao
aAdd(aCab, {"A1_CGC", StrTran(StrTran(StrTran(oLegacy["cnpj"], ".", ""), "/", ""), "-", ""), NIL})
aAdd(aCab, {"A1_END", AllTrim(oLegacy["endereco"]), NIL})
aAdd(aCab, {"A1_EMAIL", Lower(AllTrim(oLegacy["email"])), NIL})
// Default values
aAdd(aCab, {"A1_TIPO", "F", NIL})
aAdd(aCab, {"A1_INSCR", "ISENTO", NIL})
Return aCab
Load: inserir via MsExecAuto
User Function ImportClientesLegacy()
Local nOk := 0, nErro := 0
Local aErros := {}
// Conecta no legado
nConn := TCLink("ODBC_LEGACY", "DB_LEGACY", "user", "pass")
TCSetConn(nConn)
TCQuery "SELECT * FROM clientes WHERE migrado = 0" New Alias "L"
While !L->(Eof())
// Cache do registro legado
oLegacy := JsonObject():New()
oLegacy["nome"] := L->nome
oLegacy["cnpj"] := L->cnpj
oLegacy["endereco"] := L->endereco
oLegacy["email"] := L->email
oLegacy["tipo"] := L->tipo
oLegacy["id_orig"] := L->id
// Volta pra conexao Protheus
TCSetConn(0)
// Insere via MsExecAuto
Local aCab := MapearCliente(oLegacy)
Private lMsErroAuto := .F.
MsExecAuto({|x,y| Mata030(x,y)}, aCab, 3) // 3 = incluir
If lMsErroAuto
nErro++
aAdd(aErros, {oLegacy["id_orig"], MostraErro()})
DisarmTransaction()
Else
nOk++
// Marcar como migrado no legado
TCSetConn(nConn)
TCSqlExec("UPDATE clientes SET migrado = 1 WHERE id = " + cValToChar(oLegacy["id_orig"]))
EndIf
// Loop: volta pra legado
TCSetConn(nConn)
L->(DBSkip())
EndDo
L->(DBCloseArea())
TCSetConn(0)
TCUnLink(nConn)
ConOut("Migrados OK: " + cValToChar(nOk))
ConOut("Erros: " + cValToChar(nErro))
// Gera relatorio de erros
If Len(aErros) > 0
U_LogErrosETL(aErros)
EndIf
Return
Padroes essenciais
1. Idempotencia
Rodou 2x? Nao duplica. Use flag no legado (migrado = 1) ou marker no Protheus (A1_LEGACYID).
2. Batch processing
Em base com 100k+ registros, processe em lotes de 1000 com transacao explicita.
Begin Transaction
// 1000 inclusoes
End Transaction
// Commit, prossegue para proximo lote
3. Logging detalhado
Cada falha → log com contexto pra investigacao posterior.
4. Dry run mode
Private lDryRun := .T. // Em primeiro teste
If lDryRun
ConOut("[DRY-RUN] Inseriria: " + oLegacy["nome"])
Else
MsExecAuto(...)
EndIf
5. Reconciliacao
Apos migracao, conte registros nos dois lados — devem bater.
Pegadinhas comuns
- Encoding: legado em latin1, Protheus em UTF-8? Caracteres especiais quebram. Use iconv ou TCConvCharset.
- Chaves duplicadas: CNPJ ja existe? Skip ou atualizar — defina politica.
- Campos obrigatorios: Protheus rejeita se A1_NOME vazio. Validacoes prevenem isso.
- Performance: 100k inclusoes podem demorar horas. Particionar entre filiais.
- Rollback parcial: se quebrar no meio, planeje como retomar do ponto.
Ferramentas alternativas
- TOTVS Carol: ETL gerenciado da TOTVS, suporte oficial
- Pentaho: open source, GUI visual
- Talend: ETL profissional
- Python + SQLAlchemy: customizacoes pesadas