Nesta página8 seções
Antes de começar
- Tabela customizada criada no dicionário (no exemplo, a ZA1 — Cadastro de motoristas)
- Acesso ao Configurador com permissão de alterar o dicionário de dados
O campo data do Protheus (tipo D) aparece na tela como 15/03/1988 e fica
no banco como o texto 19880315. Na tela e no AdvPL ele é uma data de
verdade, que soma dias e compara com outra data. No banco é uma cadeia de 8
posições no formato AAAAMMDD. E ele não guarda hora.
Quase todo erro com data em consulta SQL vem de esquecer uma dessas duas
coisas. O exemplo é o nascimento do motorista, na tabela ZA1 da série: um
campo obrigatório que só pode ser preenchido na inclusão.
Criando o campo no Configurador
- No Configurador, abra Base de Dados > Dicionário > Arquivos.
- Posicione na tabela
ZA1e clique em Editar. - Abra a pasta Campos e clique em Incluir.
- A tela de inclusão tem as pastas Campo, Informações, Opções,
Validações, Uso e Módulos. Preencha:
- Nome e tipo:
ZA1_NASC, tipo Data. Todo campo data tem tamanho 8 e nenhuma decimal. - Informações: título (até 12 caracteres), descrição (até 25) e o help que o usuário vê ao apertar F1 sobre o campo. Há um título e uma descrição para português, espanhol e inglês.
- Validações: nada por enquanto. A regra de idade mínima,
U_ZA1VldIdade()noX3_VALID, entra no artigo de validação de campo, depois que a função existir. - Uso: marque Obrigatório. Quando o usuário deixa o campo vazio numa inclusão ou alteração, o sistema avisa e destaca o campo. Marque também Browse, para a data aparecer na lista.
- Nome e tipo:
- Confirme.
O modo de edição (Inclui) e as demais propriedades estão na ficha abaixo.
A ficha do ZA1_NASC
| Propriedade (coluna da SX3) | Valor |
|---|---|
Tipo (X3_TIPO) | D |
Tamanho (X3_TAMANHO) | 8 |
Decimais (X3_DECIMAL) | 0 |
Título (X3_TITULO) | Nascimento |
Descrição (X3_DESCRIC) | Data de nascimento |
Formato (X3_PICTURE) | em branco |
Modo de edição (X3_WHEN) | Inclui |
Alterar/Visualizar (X3_VISUAL) | A |
| Obrigatório (pasta Uso) | marcado |
Browse (X3_BROWSE) | S |
Contexto (X3_CONTEXT) | R |
Proprietário (X3_PROPRI) | U |
A máscara fica em branco porque a maior parte dos campos data do dicionário
padrão também não tem. X3_VISUAL = A deixa o campo editável, e o
X3_WHEN, explicado adiante, decide quando ele abre.
A idade do motorista, ZA1_IDADE, é preenchida a partir deste campo por um
gatilho. O campo numérico está em
Campo numérico,
e o gatilho em
Gatilhos no Protheus.
O que o banco grava
A data vai para o banco como string AAAAMMDD. O nascimento digitado como
15/03/1988 fica 19880315. Na base SQL Server de demonstração que
conferimos, a coluna de um campo data é varchar(8), e uma data vazia não é
NULL: são oito espaços.
Duas consequências práticas:
- Comparar e ordenar funciona, porque
AAAAMMDDem ordem alfabética é a mesma coisa que ordem cronológica.'19880315' < '19900101'é verdadeiro. - Formato de tela não funciona em SQL.
'15/03/1988'não bate com nada gravado. A data vai sempre comoAAAAMMDD, entre aspas.
Motoristas nascidos a partir de 1990:
SELECT ZA1_COD, ZA1_NOME, ZA1_NASC
FROM ZA1010
WHERE ZA1_NASC >= '19900101'
AND D_E_L_E_T_ = ' '
ORDER BY ZA1_NASCMotoristas sem data preenchida:
SELECT ZA1_COD, ZA1_NOME
FROM ZA1010
WHERE ZA1_NASC = ' '
AND D_E_L_E_T_ = ' 'O 010 do nome da tabela é o sufixo da empresa e muda de ambiente para
ambiente. Troque pelo seu.
Para ver o tipo físico no seu banco:
SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'ZA1010'
AND COLUMN_NAME = 'ZA1_NASC'Quando precisa de hora
O campo D não salva hora. Quando o registro precisa de data e hora, o
padrão usa dois campos: um data e um caractere para a hora. O A1S_HORA, por
exemplo, é caractere de 5 posições, máscara de hora e inicializador
LEFT(TIME(),5), que pega a hora do momento no formato HH:MM.
Para o motorista, isso seria um ZA1_HRCAD caractere de 5 ao lado de uma
data de cadastro. Como os dois são texto, a ordem cronológica em SQL sai de
ORDER BY data, hora.
Ida e volta em AdvPL
Lido pela tabela (ZA1->ZA1_NASC), o campo já chega como data. Numa query,
ele volta como texto de 8 posições. O caminho completo é DToS() na ida,
para montar o filtro, e SToD() na volta, para voltar a ter data:
// dCorte chega de fora: parâmetro da rotina, pergunta do relatório etc.
Static Function ListaNasc(dCorte)
Local cQuery := ""
Local cAlias := GetNextAlias()
Local dNasc := CToD("")
cQuery := "SELECT ZA1_COD, ZA1_NASC FROM " + RetSqlName("ZA1")
cQuery += " WHERE ZA1_NASC <= '" + DToS(dCorte) + "'"
cQuery += " AND D_E_L_E_T_ = ' '"
DbUseArea(.T., "TOPCONN", TcGenQry(,, cQuery), cAlias)
While !(cAlias)->(Eof())
dNasc := SToD((cAlias)->ZA1_NASC) // texto "19880315" vira data
// dNasc agora aceita conta: dDataBase - dNasc devolve dias
(cAlias)->(DbSkip())
EndDo
(cAlias)->(DbCloseArea())
ReturnDToC() e CToD() servem para mostrar data ao usuário e dependem do formato
de data da sessão. Para SQL, use DToS() e SToD(). A conversão por
TCSetField e o MPSysOpenQuery, alternativas ao SToD linha a linha,
estão em
Tipos de dados em AdvPL.
Os índices do padrão seguem a mesma lógica. A chave do índice 2 do pedido de
venda é C5_FILIAL+DTOS(C5_EMISSAO)+C5_NUM: a data entra na chave já
convertida em texto.
Inclui no modo de edição
O modo de edição (X3_WHEN) recebe uma expressão lógica. Enquanto ela for
.T., o campo aceita digitação. Quando for .F., fica bloqueado. Com
Inclui, a expressão inteira é a variável:
IncluiInclui é a variável que as rotinas de cadastro usam para dizer que a
operação corrente é uma inclusão. As rotinas do padrão fazem
INCLUI := .T. e INCLUI := .F. explicitamente. Ela é .T. ao incluir, e o
campo fica aberto. É .F. ao alterar, e o campo fica travado com o valor que
já tem.
Não é invenção de customização. O dicionário padrão tem campos data com
X3_WHEN igual a INCLUI, e a mesma variável aparece em inicializadores do
padrão, como no B1_OBS: If(!inclui,MSMM(SB1->B1_CODOBS,60),"").
Outras expressões para o mesmo campo, e o que muda entre X3_WHEN e a
propriedade Alterar/Visualizar, estão em
Modo de edição (X3_WHEN).
Data de hoje como valor inicial
Quando a data deve nascer preenchida, o inicializador padrão (X3_RELACAO)
recebe dDataBase. É assim que o C5_EMISSAO do pedido vem preenchido: o
inicializador dele é ddatabase.
dDataBase é a data-base da sessão, não a data do servidor, que é a que
Date() devolve. Algumas rotinas do padrão reatribuem a data-base durante o
processamento, então não a trate como constante. Para o nascimento não faz
sentido, mas para data de cadastro, de emissão ou de movimento é o padrão.
Conferir o dicionário
SELECT X3_CAMPO, X3_TIPO, X3_TAMANHO, X3_PICTURE, X3_WHEN, X3_VISUAL, X3_BROWSE,
X3_VALID
FROM SX3010
WHERE X3_ARQUIVO = 'ZA1'
AND X3_TIPO = 'D'
AND D_E_L_E_T_ = ' 'Referências
TDNtdn.totvs.com
TDN — Tipos de dados (Dicionário de Dados)TDNtdn.totvs.com
TDN — Campos (CFGX034 - SIGACFG)TDNtdn.totvs.com
TDN — Pasta Informações (CFGX034 - SIGACFG)TDNtdn.totvs.com
TDN — Pasta Uso (CFGX034 - SIGACFG)TDNtdn.totvs.com
TDN — DToS
Continue por aqui
- Vídeo
ProtheusReferência técnica
Os cinco tipos de campo do Protheus e o que cada um grava no banco
Os cinco tipos de campo do Protheus: caractere, numérico, data, lógico e memo. O que a SQL devolve de cada um e as armadilhas de data, lógico e memo.