Pragiva — Tecnologia na prática

Campo data: o que a tela mostra e o que o banco grava

Campo data no Protheus: a tela mostra DD/MM/AAAA, o banco grava texto AAAAMMDD sem hora. Como criar, liberar edição só na inclusão e comparar em SQL.

Protheus Tutorial 5 min de leitura

Assista o vídeo

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

  1. No Configurador, abra Base de Dados > Dicionário > Arquivos.
  2. Posicione na tabela ZA1 e clique em Editar.
  3. Abra a pasta Campos e clique em Incluir.
  4. 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() no X3_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.
  5. 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 AAAAMMDD em 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 como AAAAMMDD, entre aspas.

Motoristas nascidos a partir de 1990:

Confira no seu ambienteSQL
SELECT ZA1_COD, ZA1_NOME, ZA1_NASC
  FROM ZA1010
 WHERE ZA1_NASC >= '19900101'
   AND D_E_L_E_T_ = ' '
 ORDER BY ZA1_NASC

Motoristas sem data preenchida:

Confira no seu ambienteSQL
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:

Confira no seu ambienteSQL
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 , 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:

ADVPL / TLPP
// 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())

Return

DToC() 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:

TEXT
Inclui

Inclui é 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 : 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 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

Confira no seu ambienteSQL
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

  1. TDNtdn.totvs.com

    TDN — Tipos de dados (Dicionário de Dados)
  2. TDNtdn.totvs.com

    TDN — Campos (CFGX034 - SIGACFG)
  3. TDNtdn.totvs.com

    TDN — Pasta Informações (CFGX034 - SIGACFG)
  4. TDNtdn.totvs.com

    TDN — Pasta Uso (CFGX034 - SIGACFG)
  5. TDNtdn.totvs.com

    TDN — DToS

Continue por aqui