Resposta rápida
- Onde fica
- coluna
X3_CONTEXTdaSX3—Rpara real,Vpara virtual. - Real
- vira coluna na tabela física; o valor é gravado e o SQL enxerga.
- Virtual
- não vira coluna; o valor é montado na tela, em geral pelo inicializador (
X3_RELACAO). - Armadilha
- campo virtual não entra em
SELECT, relatório por SQL nem integração que lê o banco.
Real quando o dado nasce ali; virtual quando o dado já existe em outra tabela e só precisa aparecer.
Consulta rápida5 seções
A pergunta que o contexto responde é uma só: esse campo vai existir na tabela do banco? Se sim, é real. Se ele só precisa aparecer na tela — mostrando uma informação que já mora em outro lugar —, é virtual.
O que cada contexto grava
Real (R) | Virtual (V) | |
|---|---|---|
| Coluna na tabela física | Sim | Não |
| Valor gravado no registro | Sim | Nunca |
Aparece em SELECT | Sim | Não — a coluna não existe |
| De onde vem o valor na tela | Do registro gravado (ou do inicializador, na inclusão) | Da expressão do inicializador, a cada exibição |
| Uso típico | Dado que nasce no cadastro | Descrição, nome ou saldo buscado de outra tabela |
Numa base Protheus 12 conferida para este artigo, os campos das tabelas SA1, SB1,
SC5 e SC6 batem exatamente com essa tabela: todo campo com
X3_CONTEXT = 'V' está ausente da tabela física, e todo campo real está
presente.
Como o padrão monta um campo virtual
Os virtuais do dicionário padrão seguem um desenho repetido. Três exemplos reais:
| Campo | O que mostra | X3_RELACAO |
|---|---|---|
B1_GRPTIDC | Descrição do grupo, da tabela genérica XJ da SX5 | IIF(!INCLUI,POSICIONE("SX5",1,XFILIAL("SX5")+"XJ"+SB1->B1_GRPTI,"X5_DESCRI"),"") |
C5_NOMMOT | Nome do motorista do pedido, de outra tabela | IF(!INCLUI,Posicione("DHB",1,xFilial("DHB")+SC5->C5_CODMOT,"DHB_NOMMOT"),"") |
C6_SLDALIB | Saldo a liberar do item, calculado por função | Ma440SaLib() |
Três leituras que valem para qualquer virtual seu:
- Quem alimenta o campo é o inicializador padrão (
X3_RELACAO). No virtual, ele é a fonte do dado. Quando e como ele roda está em Inicializador padrão e de browse. Posicione(alias, ordem, chave, campo)é a busca típica: abre a tabela de origem pelo índice indicado, procura a chave e devolve o campo pedido.- O
!INCLUInão é enfeite. Na inclusão o registro ainda não existe, eSC5->C5_CODMOTaponta para o que estiver posicionado na tabela — não para o pedido que está sendo digitado. Por isso o padrão só busca fora da inclusão e, na inclusão, devolve vazio.
Os três vêm com X3_VISUAL = 'V': o usuário vê, mas não digita. Para um
virtual de consulta, é o certo — nada do que ele digitasse iria para a tabela.
Exemplo: o nome do motorista no pedido de venda
No exemplo da série, uma transportadora cadastra motoristas numa tabela
customizada ZA1 e informa o motorista do pedido de venda num campo
customizado real, C5_XMOTOR (C 6, com consulta padrão ZA1). O código fica
gravado no pedido. O nome não precisa ser gravado de novo: ele já está em
ZA1_NOME.
Então o nome entra como virtual, com o mesmo recurso do C5_NOMMOT do padrão
(campo virtual com Posicione no inicializador). O tamanho segue o do
ZA1_NOME:
| Item | Valor |
|---|---|
| Campo | C5_XNOMMOT |
| Tipo / tamanho | C 40 (o mesmo de ZA1_NOME) |
Contexto (X3_CONTEXT) | Virtual |
Visual (X3_VISUAL) | Visualizar |
Inicializador padrão (X3_RELACAO) | IIF(!INCLUI,Posicione("ZA1",1,xFilial("ZA1")+SC5->C5_XMOTOR,"ZA1_NOME"),"") |
O índice 1 da ZA1 é ZA1_FILIAL+ZA1_COD, por isso a chave é
xFilial("ZA1") seguido do código. xFilial(cAlias, cFil) devolve a
filial certa para aquela tabela: sem o segundo parâmetro, usa a filial
corrente; em tabela compartilhada, como a ZA1, devolve brancos.
A documentação TOTVS sobre pesquisa por campo virtual no browse faz uma
exigência para o Posicione do virtual: xFilial só com o primeiro
parâmetro, e nada de FwXFilial. Fora disso, o campo continua mostrando o
conteúdo, mas não entra na pesquisa do browse.
Isso cobre alteração e visualização. Na inclusão, o nome precisa aparecer
quando o usuário digita o código — e aí quem preenche é um gatilho de
C5_XMOTOR para C5_XNOMMOT, que posiciona na ZA1 e devolve ZA1->ZA1_NOME.
O padrão usa esse par em outros cadastros: no de clientes, o A1_REGDES é
virtual, com Posicione no inicializador para o registro existente, e um
gatilho do A1_CDRDES o preenche durante a digitação. O C5_NOMMOT tem só uma
metade do par, o inicializador; não há gatilho para ele no dicionário padrão. A montagem
do gatilho está em
Gatilhos no Protheus.
Se você renomear o motorista na ZA1, todo pedido passa a mostrar o nome novo
na próxima abertura. Com um campo real, cada pedido guardaria o nome da época —
e alguém teria que escrever a rotina que atualiza os antigos.
Real ou virtual: como decidir
Use real quando:
- o dado nasce naquele registro (número, data, quantidade, observação);
- relatório, query, BI ou integração precisam ler o valor no banco;
- o valor precisa ser o da época — o nome do motorista no dia da viagem, por exemplo, e não o nome atual.
Use virtual quando:
- o dado já existe em outra tabela e só precisa aparecer ao lado do código;
- o valor é calculado e mudaria sozinho (saldo, situação);
- gravar a cópia criaria a obrigação de mantê-la sincronizada.
Conferindo no banco
Os campos virtuais de uma tabela, lado a lado com a coluna física (que não
existe para eles). Os exemplos usam o sufixo 010; o sufixo muda conforme a
empresa do seu ambiente. A consulta usa INFORMATION_SCHEMA.COLUMNS como no
SQL Server; em outro banco, troque pela visão de colunas equivalente.
SELECT X3.X3_CAMPO, X3.X3_CONTEXT, X3.X3_RELACAO, C.COLUMN_NAME
FROM SX3010 X3
LEFT JOIN INFORMATION_SCHEMA.COLUMNS C
ON C.TABLE_NAME = 'SC5010'
AND C.COLUMN_NAME = RTRIM(X3.X3_CAMPO)
WHERE X3.X3_ARQUIVO = 'SC5'
AND X3.X3_CONTEXT = 'V'
AND X3.D_E_L_E_T_ = ' '
ORDER BY X3.X3_ORDEME a prova mais direta: um SELECT C5_NOMMOT FROM SC5010 falha com coluna
inválida. Para levar a informação de um virtual para um relatório por SQL, faça
na query o que o inicializador faz na tela — um JOIN com a tabela de origem.
Se você está decidindo o contexto de campos de uma customização grande, fale com a gente.
Referências
TDNtdn.totvs.com
TDN — SX3, Campos das tabelasTDNtdn.totvs.com
TDN — Posicione com Campo Virtual
Continue por aqui
- Vídeo
ProtheusTutorial
Campo memo: texto longo que o SQL não lê direto
Campo memo no Protheus guarda texto livre, mas no SQL Server a coluna é binária e um SELECT simples devolve bytes. Memo real x memo virtual na SYP.