| Bellacosa Mainframe e a classificacao de datasets via sort |
☕ Um Café no Bellacosa Mainframe
SORT — O Pelotão que Colocava o Caos em Ordem
Como DFSORT, ICETOOL, arquivos temporários e algumas linhas de JCL reorganizam milhões de registros enquanto o recruta tenta sobreviver à sua primeira madrugada no CPD
“No batch, ninguém abandona um registro para trás.”
A sala de operações estava quase vazia.
Eram duas e quarenta e sete da manhã quando o recruta recebeu sua primeira missão de verdade. Não era um programa COBOL elegante, não havia tela CICS piscando nem banco de dados esperando um COMMIT.
Havia apenas um arquivo.
Um arquivo enorme.
Milhões de registros de transações, clientes, datas, agências e valores haviam chegado completamente fora de ordem. Alguns registros estavam duplicados. Outros deveriam ser eliminados. Certas colunas precisavam mudar de posição. O departamento financeiro queria um relatório por agência, em ordem de data e valor.
E queria antes das seis da manhã.
O veterano olhou para o recruta como o sargento Elias observando um soldado recém-chegado à selva de Platoon.
— Você sabe usar o SORT?
O jovem respirou fundo.
— Sei colocar em ordem crescente.
O veterano apagou o cigarro imaginário no cinzeiro do CPD.
— Então você ainda não sabe usar o SORT.
1. O que é o SORT no mainframe?
No universo IBM z/OS, quando alguém diz simplesmente SORT, normalmente está falando de uma família de operações capazes de:
classificar registros;
copiar arquivos;
mesclar arquivos previamente ordenados;
selecionar ou eliminar registros;
remover duplicidades;
somar campos numéricos;
reformatar registros;
criar vários arquivos de saída;
gerar relatórios;
contar registros;
comparar arquivos;
cruzar dois datasets por meio de chaves;
inserir cabeçalhos e rodapés;
converter formatos;
criar sequências;
procurar e substituir conteúdo.
Na plataforma IBM, a implementação mais conhecida é o DFSORT, produto de alto desempenho destinado a classificação, cópia, mesclagem, análise e geração de relatórios em z/OS. Apesar de seu nome histórico, ele está muito longe de ser apenas um classificador. (IBM)
Dependendo da instalação, também pode existir outro produto compatível, como o Syncsort/MFX. A sintaxe básica costuma ser semelhante, mas opções avançadas, mensagens e comportamentos podem variar.
Por isso, uma das primeiras regras do recruta é:
Antes de copiar um SORT encontrado na internet, descubra qual produto está instalado em seu ambiente.
2. A origem: antes do silício, já existia o problema da ordem
A necessidade de ordenar informações é muito anterior ao computador.
Bibliotecas classificavam livros. Bancos organizavam fichas de clientes. Governos agrupavam registros populacionais. Empresas separavam cartões perfurados por código, região, conta ou data.
Nas antigas instalações de processamento de dados, máquinas classificadoras eletromecânicas liam cartões perfurados e os distribuíam fisicamente em compartimentos. Para ordenar por vários campos, os cartões podiam passar diversas vezes pela máquina.
Primeiro uma coluna.
Depois outra.
Depois outra.
Era uma coreografia mecânica de papel, engrenagens e eletricidade.
Quando os computadores eletrônicos assumiram o processamento comercial, aquela necessidade permaneceu. O suporte mudou — cartões, fitas magnéticas, discos, datasets —, mas a missão continuou a mesma:
Receber dados desordenados e entregá-los na sequência necessária ao processamento seguinte.
Em ambientes batch, a ordenação tornou-se fundamental porque muitos programas foram projetados para trabalhar com arquivos em sequência de chave.
Um programa COBOL poderia, por exemplo:
ler um arquivo de clientes em ordem de número de conta;
ler um arquivo de movimentos na mesma ordem;
comparar as chaves;
aplicar os movimentos ao cliente correspondente;
produzir um novo arquivo mestre.
Sem a classificação prévia, esse casamento sequencial seria caótico.
O SORT tornou-se, portanto, uma espécie de pelotão de logística do mainframe. Ele não aparece na linha de frente das aplicações, mas prepara o terreno para que todo o restante funcione.
3. Anatomia de uma missão SORT
Um passo básico de DFSORT em JCL costuma ter quatro elementos:
//ORDENA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=VAGNER.ARQUIVO.ENTRADA,DISP=SHR
//SORTOUT DD DSN=VAGNER.ARQUIVO.SAIDA,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(10,5),RLSE),
// DCB=(RECFM=FB,LRECL=100,BLKSIZE=0)
//SYSIN DD *
SORT FIELDS=(1,10,CH,A)
/*
O papel de cada DD
EXEC PGM=SORT
Executa o utilitário de classificação definido pela instalação.
Em muitos ambientes também aparece:
//ORDENA EXEC PGM=ICEMAN
ICEMAN é um nome tradicionalmente associado ao programa do DFSORT, mas PGM=SORT é mais legível e costuma ser preferido em JCL de aplicação.
SYSOUT
Recebe mensagens produzidas pelo utilitário:
//SYSOUT DD SYSOUT=*
É aqui que o recruta descobrirá:
quantos registros foram lidos;
quantos foram gravados;
quais opções foram utilizadas;
se houve alocação dinâmica;
qual foi o return code;
qual mensagem explica o desastre.
Nunca despreze o SYSOUT.
No campo de batalha do batch, ele é o relatório da patrulha.
SORTIN
É o dataset de entrada:
//SORTIN DD DSN=VAGNER.ARQUIVO.ENTRADA,DISP=SHR
SORTOUT
É o arquivo principal de saída:
//SORTOUT DD DSN=VAGNER.ARQUIVO.SAIDA,...
SYSIN
Contém as instruções de controle:
//SYSIN DD *
SORT FIELDS=(1,10,CH,A)
/*
É no SYSIN que a missão é descrita.
4. Decifrando SORT FIELDS
Observe:
SORT FIELDS=(1,10,CH,A)
A estrutura é:
posição, tamanho, formato, ordem
Portanto:
1,10,CH,A
significa:
começar na posição 1;
usar 10 bytes;
interpretar como caracteres;
ordenar de forma ascendente.
Ordem ascendente e descendente
A = Ascending
D = Descending
Exemplo:
SORT FIELDS=(1,10,CH,A)
Ordena nomes da posição 1 à 10 em ordem crescente.
SORT FIELDS=(1,10,CH,D)
Ordena em ordem decrescente.
5. Ordenação com várias chaves
Imagine este layout:
| Posição | Tamanho | Campo |
|---|---|---|
| 1 | 4 | Agência |
| 5 | 8 | Data AAAAMMDD |
| 13 | 10 | Número da conta |
| 23 | 9 | Valor |
| 32 | 1 | Tipo |
Queremos ordenar:
por agência crescente;
dentro da agência, por data crescente;
dentro da data, por valor decrescente.
//SYSIN DD *
SORT FIELDS=(1,4,CH,A,
5,8,CH,A,
23,9,ZD,D)
/*
O DFSORT aplica as chaves da esquerda para a direita.
É como organizar um pelotão:
primeiro por companhia;
depois por esquadrão;
finalmente por graduação.
6. Os principais formatos de dados
O SORT precisa saber como interpretar os bytes.
A sequência hexadecimal que representa o número 123 em display não é a mesma representação de um campo binário ou packed decimal.
Entre os formatos suportados estão diversos tipos de caracteres, binários e decimais. O formato CH, por exemplo, trata cada caractere segundo seu código EBCDIC. (IBM)
Formatos comuns
CH — Character
1,20,CH,A
Usado para campos alfanuméricos em EBCDIC.
ZD — Zoned Decimal
Muito comum em arquivos originados por COBOL:
05 WS-VALOR PIC 9(9).
No SORT:
23,9,ZD,D
PD — Packed Decimal
Corresponde normalmente a campos COBOL COMP-3.
05 WS-VALOR PIC S9(9)V99 COMP-3.
O tamanho físico não é 11 bytes. Para 11 dígitos, o campo packed ocupa:
(11 + 1) / 2 = 6 bytes
Exemplo:
23,6,PD,D
BI — Binary
Trata o campo como binário sem sinal.
FI — Fixed-point signed
Usado em certos campos binários com sinal.
UFF e SFF
Úteis para números em formato livre, com espaços ou sinais em diferentes posições.
7. A armadilha do recruta: ordenar números como caracteres
Considere:
1
2
10
20
100
Se os valores ocuparem campos de tamanho variável ou não estiverem preenchidos corretamente, uma classificação alfanumérica pode produzir algo semelhante a:
1
10
100
2
20
Isso ocorre porque a comparação está sendo feita byte a byte, como texto.
Para números, use o formato correspondente à representação física real:
SORT FIELDS=(1,5,ZD,A)
Mas atenção:
Não escolha
ZD,PDouBIpelo significado lógico do campo. Escolha pela forma como ele está fisicamente gravado.
Um valor pode ser conceitualmente numérico e, ainda assim, estar armazenado como caracteres.
8. Como descobrir as posições dos campos
Suponha o copybook:
01 REGISTRO-CLIENTE.
05 CLI-AGENCIA PIC X(04).
05 CLI-CONTA PIC X(10).
05 CLI-NOME PIC X(30).
05 CLI-SALDO PIC S9(09)V99 COMP-3.
05 CLI-STATUS PIC X(01).
Calculando as posições:
| Campo | Posição | Tamanho físico |
|---|---|---|
| CLI-AGENCIA | 1 | 4 |
| CLI-CONTA | 5 | 10 |
| CLI-NOME | 15 | 30 |
| CLI-SALDO | 45 | 6 |
| CLI-STATUS | 51 | 1 |
Para ordenar por agência, saldo decrescente e conta:
SORT FIELDS=(1,4,CH,A,
45,6,PD,D,
5,10,CH,A)
Regra de ouro
Antes de escrever o SORT:
obtenha o copybook;
confirme o
RECFM;confirme o
LRECL;calcule a posição física;
verifique campos
COMP,COMP-3e redefinições;confirme se existe RDW em registros variáveis;
examine uma amostra em hexadecimal.
O programador que não olha os dados em hexadecimal está entrando na selva sem mapa.
9. Arquivos FB e VB: a história dos quatro bytes invisíveis
Arquivo FB
Em um dataset RECFM=FB, todos os registros têm tamanho fixo.
Se o LRECL é 100, o primeiro campo começa normalmente na posição 1 do registro lógico.
SORT FIELDS=(1,10,CH,A)
Arquivo VB
Em um dataset RECFM=VB, cada registro físico começa com um Record Descriptor Word, o famoso RDW.
O RDW ocupa quatro bytes.
Por isso, em muitas instruções DFSORT para arquivos variáveis, os dados começam na posição 5.
Se o campo lógico está no início do registro de aplicação, a chave poderá ser:
SORT FIELDS=(5,10,CH,A)
Este é um dos erros clássicos de iniciantes.
O recruta vê o copybook dizendo que o campo começa na posição 1 e escreve:
1,10,CH,A
Mas, no contexto do SORT para VB, acaba incluindo os bytes do RDW.
O resultado pode ser:
classificação absurda;
erro de campo além do registro;
comportamento variável;
longas horas procurando um problema que estava quatro bytes antes.
10. SORT FIELDS=COPY: quando não queremos classificar
DFSORT também pode apenas copiar registros:
//COPIA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=VAGNER.CLIENTES,DISP=SHR
//SORTOUT DD DSN=VAGNER.CLIENTES.COPIA,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(5,2),RLSE),
// UNIT=SYSDA,
// DCB=*.SORTIN
//SYSIN DD *
SORT FIELDS=COPY
/*
Também pode ser usado:
OPTION COPY
A cópia parece banal, mas é extremamente poderosa quando combinada com:
INCLUDE;OMIT;INREC;OUTREC;OUTFIL;FINDREP;IFTHEN.
É comum usar DFSORT apenas como um transformador de arquivos, sem alterar a ordem.
11. Selecionando registros com INCLUDE
Imagine que o status esteja na posição 51.
Queremos somente clientes ativos:
INCLUDE COND=(51,1,CH,EQ,C'A')
SORT FIELDS=COPY
Operadores de comparação
EQ = Equal
NE = Not equal
GT = Greater than
GE = Greater than or equal
LT = Less than
LE = Less than or equal
Exemplo com mais de uma condição
Selecionar:
status ativo;
saldo maior que zero.
INCLUDE COND=(51,1,CH,EQ,C'A',AND,
45,6,PD,GT,+0)
SORT FIELDS=(1,4,CH,A)
Uso de OR
INCLUDE COND=(51,1,CH,EQ,C'A',OR,
51,1,CH,EQ,C'P')
SORT FIELDS=COPY
Aceita status A ou P.
12. Eliminando registros com OMIT
Se a missão for remover cancelados:
OMIT COND=(51,1,CH,EQ,C'C')
SORT FIELDS=COPY
Nunca use INCLUDE e OMIT simultaneamente no mesmo nível de controle. Escolha a lógica mais clara.
Como regra de manutenção:
use
INCLUDEquando poucos registros devem passar;use
OMITquando poucos registros devem ser descartados.
13. Constantes no SORT
Caracteres
C'ATIVO'
Hexadecimal
X'F1F2F3'
Decimal positivo
+100
Decimal negativo
-50
Exemplo:
INCLUDE COND=(1,3,CH,EQ,C'BRA')
14. Removendo registros duplicados
Considere um arquivo ordenado por conta.
Queremos manter apenas um registro para cada conta:
SORT FIELDS=(5,10,CH,A)
SUM FIELDS=NONE
SUM FIELDS=NONE elimina registros cujas chaves de classificação sejam duplicadas.
Mas há uma pergunta perigosa:
Qual registro duplicado será mantido?
Isso depende das opções de estabilidade e da estratégia utilizada.
Para preservar a ordem relativa original de registros com a mesma chave, pode-se usar:
OPTION EQUALS
SORT FIELDS=(5,10,CH,A)
SUM FIELDS=NONE
EQUALS ajuda a preservar a ordem de entrada entre registros com chaves iguais.
Mesmo assim, não trate a seleção de “primeiro” ou “último” duplicado como acidente. Quando a regra de negócio depende disso, torne-a explícita adicionando uma chave complementar, como data ou timestamp.
Exemplo: manter o movimento mais recente.
SORT FIELDS=(5,10,CH,A,
60,14,CH,D)
SUM FIELDS=NONE
Aqui:
conta crescente;
timestamp decrescente;
o registro mais recente aparece primeiro dentro da conta;
os demais duplicados são eliminados.
15. Somando valores com SUM
Suponha:
agência: posição 1, tamanho 4;
valor packed: posição 45, tamanho 6.
Queremos consolidar o valor total por agência:
SORT FIELDS=(1,4,CH,A)
SUM FIELDS=(45,6,PD)
Todos os registros com a mesma chave serão consolidados, e o valor será somado.
É essencial verificar:
capacidade do campo de saída;
sinal;
casas decimais implícitas;
possível overflow;
existência de outros campos não pertencentes à chave.
Campos não somados poderão vir de um dos registros do grupo. Portanto, não presuma que todo o conteúdo do registro consolidado terá significado lógico.
16. INREC: preparando o soldado antes da batalha
INREC reformata cada registro antes da classificação principal.
O fluxo conceitual é:
Entrada
↓
INCLUDE/OMIT
↓
INREC
↓
SORT ou MERGE
↓
SUM
↓
OUTREC
↓
OUTFIL
↓
Saída
A documentação IBM explica que INREC é processado antes de SORT, SUM e OUTREC, mas depois das condições INCLUDE ou OMIT. (IBM)
Exemplo
Arquivo original:
| Campo | Posição | Tamanho |
|---|---|---|
| Conta | 1 | 10 |
| Nome | 11 | 30 |
| Agência | 41 | 4 |
| Saldo | 45 | 6 |
Queremos criar internamente:
Agência + Conta + Saldo
INREC BUILD=(41,4,
1,10,
45,6)
SORT FIELDS=(1,4,CH,A,
5,10,CH,A)
Depois do INREC, as posições mudaram.
Agora:
agência está em 1;
conta está em 5;
saldo está em 15.
Uma das maiores fontes de erro é continuar usando no SORT FIELDS as posições do registro original após um INREC.
17. OUTREC: reorganizando depois da classificação
OUTREC reformata os registros depois da operação de ordenação, cópia ou mesclagem. (IBM)
Exemplo:
SORT FIELDS=(1,4,CH,A)
OUTREC BUILD=(1,4,
C'|',
5,10,
C'|',
15,30)
Saída:
0001|1234567890|JOSE DA SILVA
0001|2234567890|MARIA DE SOUZA
Inserindo espaços
OUTREC BUILD=(10X,1,20,5X,21,10)
A documentação IBM permite inserir áreas em branco com notações como 20X ou 10X. (IBM)
Inserindo texto literal
OUTREC BUILD=(C'AGENCIA=',1,4,
C' CONTA=',5,10)
18. OVERLAY: cirurgia em posições específicas
BUILD constrói um novo registro.
OVERLAY altera partes específicas do registro, preservando o restante.
Exemplo: colocar PROCESSADO na posição 80:
SORT FIELDS=COPY
OUTREC OVERLAY=(80:C'PROCESSADO')
Exemplo: substituir um status:
OUTREC IFTHEN=(WHEN=(51,1,CH,EQ,C'A'),
OVERLAY=(51:C'X'))
19. IFTHEN: regras condicionais
É possível aplicar transformações diferentes dependendo do conteúdo.
SORT FIELDS=COPY
OUTREC IFTHEN=(WHEN=(51,1,CH,EQ,C'A'),
OVERLAY=(60:C'CLIENTE ATIVO')),
IFTHEN=(WHEN=(51,1,CH,EQ,C'I'),
OVERLAY=(60:C'CLIENTE INATIVO'))
Cláusulas IFTHEN podem selecionar grupos de registros e aplicar operações como BUILD, OVERLAY ou FINDREP. (IBM)
Outras formas úteis incluem:
WHEN=INIT
WHEN=GROUP
WHEN=ANY
WHEN=NONE
Exemplo com inicialização
OUTREC IFTHEN=(WHEN=INIT,
OVERLAY=(80:C'NAO CLASSIFICADO')),
IFTHEN=(WHEN=(51,1,CH,EQ,C'A'),
OVERLAY=(80:C'ATIVO'))
Primeiro todos recebem NAO CLASSIFICADO. Depois os ativos recebem ATIVO.
20. FINDREP: localizar e substituir
Imagine registros contendo:
SAO PAULO
Queremos trocar por:
SP
SORT FIELDS=COPY
OUTREC FINDREP=(IN=C'SAO PAULO',
OUT=C'SP')
Também pode substituir várias expressões:
OUTREC FINDREP=(INOUT=(C'SAO PAULO',C'SP',
C'RIO DE JANEIRO',C'RJ',
C'MINAS GERAIS',C'MG'))
Use com cuidado em arquivos de layout fixo. Uma substituição que muda o tamanho do conteúdo pode deslocar campos ou alterar o LRECL.
21. OUTFIL: vários destinos em uma única passagem
OUTFIL permite produzir um ou vários arquivos a partir de uma única leitura e de uma única operação principal. A IBM documenta que múltiplas instruções OUTFIL podem gerar diferentes saídas com filtros e reformatações próprias. (IBM)
Imagine um arquivo com status na posição 51.
Queremos:
ativos em
ATIVOS;inativos em
INATIVOS;cancelados em
CANCELA.
//ATIVOS DD DSN=VAGNER.CLIENTES.ATIVOS,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(5,2),RLSE),
// UNIT=SYSDA
//INATIVOS DD DSN=VAGNER.CLIENTES.INATIVOS,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(5,2),RLSE),
// UNIT=SYSDA
//CANCELA DD DSN=VAGNER.CLIENTES.CANCELADOS,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(5,2),RLSE),
// UNIT=SYSDA
//SYSIN DD *
SORT FIELDS=(1,4,CH,A)
OUTFIL FNAMES=ATIVOS,
INCLUDE=(51,1,CH,EQ,C'A')
OUTFIL FNAMES=INATIVOS,
INCLUDE=(51,1,CH,EQ,C'I')
OUTFIL FNAMES=CANCELA,
INCLUDE=(51,1,CH,EQ,C'C')
/*
Isso evita:
três leituras do arquivo;
três passos distintos;
três classificações;
consumo desnecessário de CPU e I/O.
22. SAVE: recolhendo quem ficou para trás
Depois de criar saídas específicas, podemos usar SAVE para capturar tudo que não entrou nas anteriores:
OUTFIL FNAMES=ATIVOS,
INCLUDE=(51,1,CH,EQ,C'A')
OUTFIL FNAMES=INATIVOS,
INCLUDE=(51,1,CH,EQ,C'I')
OUTFIL FNAMES=OUTROS,
SAVE
A saída OUTROS funciona como uma rede de segurança.
Em produção, ela é excelente para detectar códigos inesperados.
23. Cabeçalhos, rodapés e relatórios
O DFSORT também pode produzir relatórios.
SORT FIELDS=(1,4,CH,A)
OUTFIL FNAMES=RELATOR,
HEADER1=(C'RELATORIO DE CLIENTES'),
HEADER2=(C'AGENCIA CONTA NOME'),
TRAILER1=(C'FIM DO RELATORIO')
É possível usar recursos como:
DATE
TIME
PAGE
COUNT
TOT
MIN
MAX
AVG
Exemplo conceitual:
OUTFIL FNAMES=RELATOR,
HEADER1=(C'RELATORIO DIARIO - ',DATE),
TRAILER1=(C'TOTAL DE REGISTROS: ',COUNT)
A sintaxe exata pode variar conforme o tipo de relatório e a edição desejada.
24. MERGE: unindo pelotões já organizados
Se dois ou mais arquivos já estiverem classificados pela mesma chave, podemos mesclá-los sem realizar uma nova classificação completa.
//JUNTA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN01 DD DSN=VAGNER.MOVIMENTO.DIA1,DISP=SHR
//SORTIN02 DD DSN=VAGNER.MOVIMENTO.DIA2,DISP=SHR
//SORTOUT DD DSN=VAGNER.MOVIMENTO.CONSOLIDADO,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(20,10),RLSE),
// UNIT=SYSDA
//SYSIN DD *
MERGE FIELDS=(1,10,CH,A)
/*
Os arquivos de entrada precisam estar previamente ordenados pela chave especificada.
Não use MERGE esperando que ele conserte arquivos desordenados.
25. JOINKEYS: quando dois arquivos precisam se encontrar
JOINKEYS permite combinar registros de dois datasets por uma ou mais chaves.
É semelhante ao conceito de JOIN em SQL.
A IBM documenta suporte a combinações equivalentes a:
inner join;
left outer join;
right outer join;
full outer join;
registros pareados;
registros não pareados.
Os arquivos podem ter formatos e comprimentos diferentes. (IBM)
Exemplo: clientes e movimentos
Arquivo F1 — clientes
| Posição | Campo |
|---|---|
| 1–10 | Conta |
| 11–40 | Nome |
Arquivo F2 — movimentos
| Posição | Campo |
|---|---|
| 1–10 | Conta |
| 11–18 | Data |
| 19–27 | Valor |
//CRUZA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTJNF1 DD DSN=VAGNER.CLIENTES,DISP=SHR
//SORTJNF2 DD DSN=VAGNER.MOVIMENTOS,DISP=SHR
//SORTOUT DD DSN=VAGNER.CLIENTE.MOVIMENTO,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(10,5),RLSE),
// UNIT=SYSDA
//SYSIN DD *
JOINKEYS FILE=F1,FIELDS=(1,10,A)
JOINKEYS FILE=F2,FIELDS=(1,10,A)
REFORMAT FIELDS=(F1:1,40,
F2:11,17)
SORT FIELDS=COPY
/*
O resultado contém:
dados do cliente;
data e valor do movimento correspondente.
Apenas registros correspondentes
Esse é o comportamento básico de um inner join.
Registros sem correspondência
Para incluir não pareados:
JOIN UNPAIRED,F1,F2
Para identificar a origem, pode-se usar um indicador na reformatação:
REFORMAT FIELDS=(F1:1,40,
F2:11,17,
?)
O caractere indicador ajuda a distinguir:
registros encontrados nos dois lados;
apenas no F1;
apenas no F2.
26. Arquivos temporários no JCL
Um dataset temporário existe somente durante a execução do job.
Seu nome começa com &&.
Exemplo:
//TEMP1 DD DSN=&&CLIENTES,
// DISP=(NEW,PASS),
// UNIT=SYSDA,
// SPACE=(CYL,(10,5)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0)
&&CLIENTES
É um nome temporário.
O sistema cria um nome interno para o dataset, que será removido ao final do job.
DISP=(NEW,PASS)
NEW: o dataset será criado;PASS: se o passo terminar adequadamente, o dataset será passado para um passo seguinte.
Exemplo completo com dois passos
No primeiro passo, selecionamos clientes ativos.
No segundo, classificamos por agência.
//FILTRA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=VAGNER.CLIENTES.MESTRE,DISP=SHR
//SORTOUT DD DSN=&&ATIVOS,
// DISP=(NEW,PASS),
// UNIT=SYSDA,
// SPACE=(CYL,(10,5)),
// DCB=(RECFM=FB,LRECL=100,BLKSIZE=0)
//SYSIN DD *
INCLUDE COND=(51,1,CH,EQ,C'A')
SORT FIELDS=COPY
/*
//ORDENA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=&&ATIVOS,DISP=(OLD,DELETE)
//SORTOUT DD DSN=VAGNER.CLIENTES.ATIVOS.ORD,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(10,5),RLSE),
// DCB=(RECFM=FB,LRECL=100,BLKSIZE=0)
//SYSIN DD *
SORT FIELDS=(1,4,CH,A,
15,30,CH,A)
/*
No segundo passo:
DISP=(OLD,DELETE)
indica que o arquivo será utilizado e removido depois.
Mas o veterano perguntaria:
— Por que dois passos?
A mesma operação poderia ser feita em um:
INCLUDE COND=(51,1,CH,EQ,C'A')
SORT FIELDS=(1,4,CH,A,
15,30,CH,A)
Arquivos temporários são úteis, mas não devem substituir uma boa análise.
Use-os quando:
o resultado intermediário será utilizado por vários passos;
a separação facilita recuperação e restart;
existe necessidade operacional de inspeção;
diferentes utilitários precisam consumir o resultado;
o processo requer checkpoints;
a transformação não pode ser feita em uma única operação.
27. SORTWKnn: a trilha de suprimentos
Durante uma classificação, o DFSORT pode precisar de espaço de trabalho.
Quando os dados não cabem integralmente nas estruturas internas disponíveis, partes intermediárias são gravadas em work datasets.
Esses arquivos costumam ter DD names como:
SORTWK01
SORTWK02
SORTWK03
...
Exemplo de alocação manual:
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(500,100))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(500,100))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(500,100))
//SORTWK04 DD UNIT=SYSDA,SPACE=(CYL,(500,100))
Alocação manual ou dinâmica?
Em instalações modernas, frequentemente é melhor permitir que o DFSORT faça a alocação dinâmica.
A IBM afirma que a alocação dinâmica pode ajustar automaticamente o espaço de trabalho às características reais da aplicação, enquanto uma alocação fixa em JCL não pode ser ajustada pelo DFSORT e pode desperdiçar espaço. (IBM)
Portanto, evite copiar cegamente dezenas de SORTWKnn de um JCL antigo.
Talvez aquelas linhas tenham sido necessárias vinte anos atrás.
Talvez hoje estejam apenas ocupando espaço, limitando a otimização ou confundindo o diagnóstico.
Quando especificar manualmente?
Pode fazer sentido quando:
a instalação exige volumes específicos;
existe política local de storage;
o SORT não consegue estimar corretamente a entrada;
a alocação dinâmica está desabilitada;
há necessidade de isolar workloads;
o job apresenta falhas recorrentes de espaço;
a equipe de storage ou performance recomendou explicitamente.
Não direcione automaticamente SORTWKnn para VIO. A IBM recomenda evitar VIO para datasets temporários de trabalho do DFSORT e considerar os mecanismos próprios de memória e Hipersorting. (IBM)
28. Como o SORT trabalha com grandes datasets
Imagine um arquivo de 500 milhões de registros.
O DFSORT não precisa necessariamente carregar tudo em uma única área convencional e então “apertar um botão”.
Conceitualmente, uma classificação externa pode envolver:
leitura de blocos da entrada;
criação de sequências ordenadas intermediárias;
uso de memória e áreas de trabalho;
gravação de runs intermediários;
intercalação dessas sequências;
produção da saída final.
As implementações modernas usam diversas otimizações internas. O DFSORT pode explorar recursos como:
armazenamento virtual;
objetos de memória de 64 bits;
data spaces;
Hiperspace;
buffers;
leitura e escrita em blocos;
alocação dinâmica de work files;
estimativa do tamanho da entrada.
A IBM documenta que o DFSORT pode selecionar modos que usam objetos de memória em armazenamento virtual de 64 bits, além de outras estratégias para otimizar a classificação. (IBM)
O programador de aplicação não deve tentar adivinhar todo o algoritmo interno.
Mas precisa fornecer informações corretas.
29. Como ajudar o SORT em arquivos gigantes
29.1 Informe corretamente os atributos
Confirme:
RECFM;LRECL;tamanho estimado;
quantidade de registros;
tipo de dispositivo;
compressão;
organização;
concatenações;
entrada em fita ou disco.
29.2 Filtre o mais cedo possível
Se apenas 5% dos registros interessam, use INCLUDE antes da classificação:
INCLUDE COND=(51,1,CH,EQ,C'A')
SORT FIELDS=(1,10,CH,A)
Não classifique 500 milhões de registros para depois descartar 475 milhões.
29.3 Reduza o tamanho do registro antes de ordenar
Se a entrada possui 2.000 bytes, mas a classificação precisa de apenas 40, use INREC para reduzir o registro temporário:
INREC BUILD=(1,10,
500,8,
1500,22)
SORT FIELDS=(1,10,CH,A)
Menos bytes significam potencialmente:
menos memória;
menos I/O;
menos espaço de trabalho;
menos tempo de transferência;
menos espaço de saída intermediária.
Mas lembre-se de reconstruir o formato necessário, caso a saída precise do registro original.
29.4 Evite passos desnecessários
Ruim:
Passo 1: copiar
Passo 2: filtrar
Passo 3: ordenar
Passo 4: separar saídas
Passo 5: gerar relatório
Talvez tudo possa ser feito em um passo com:
INCLUDE
SORT
OUTREC
OUTFIL
29.5 Use MERGE quando as entradas já estiverem ordenadas
Não reordene dois arquivos gigantes se ambos já estiverem na sequência correta.
29.6 Use OUTFIL para múltiplas saídas
Evite reler o mesmo arquivo várias vezes.
29.7 Verifique a chave
Ordenar por 200 bytes quando a chave real ocupa 10 bytes aumenta o trabalho sem necessidade.
29.8 Não use parâmetros misteriosos sem medir
Parâmetros de memória, alocação e performance dependem:
da versão;
do volume;
da instalação;
do WLM;
do storage;
das opções padronizadas;
da concorrência;
do horário.
O parâmetro que salvou um job em 2009 pode degradar outro em 2026.
30. Tipos de classificação
30.1 Ascendente
SORT FIELDS=(1,10,CH,A)
30.2 Descendente
SORT FIELDS=(1,10,CH,D)
30.3 Alfanumérica
SORT FIELDS=(1,20,CH,A)
A ordem segue a representação e as regras de comparação aplicáveis, normalmente baseadas em EBCDIC para CH.
Não espere automaticamente a mesma ordem de um PC em ASCII.
30.4 Numérica display
SORT FIELDS=(1,9,ZD,A)
30.5 Packed decimal
SORT FIELDS=(1,6,PD,D)
30.6 Binária
SORT FIELDS=(1,4,BI,A)
30.7 Múltiplas chaves
SORT FIELDS=(1,4,CH,A,
5,8,CH,D,
13,6,PD,D)
30.8 Estável
OPTION EQUALS
Mantém a ordem relativa dos registros com chaves iguais, dentro das regras da operação.
30.9 Não estável
OPTION NOEQUALS
Pode permitir estratégias diferentes para registros com chaves iguais. Não dependa da ordem relativa nesse caso.
30.10 Com sequência alternativa
O SORT pode trabalhar com tabelas de tradução ou sequências de comparação específicas, conforme recursos e opções do ambiente.
31. Criando um número sequencial
É possível adicionar uma sequência aos registros:
SORT FIELDS=(1,10,CH,A)
OUTREC BUILD=(SEQNUM,8,ZD,
1,100)
Saída:
00000001...
00000002...
00000003...
Também podemos usar reinicialização por grupo em construções mais avançadas com WHEN=GROUP.
32. Agrupando registros
Considere:
HCLIENTE001
DTRANSACAO1
DTRANSACAO2
T00000002
HCLIENTE002
DTRANSACAO1
T00000001
Temos:
H: header;D: detail;T: trailer.
Com recursos de agrupamento, é possível propagar dados do header para os detalhes, numerar grupos e tratar conjuntos relacionados.
Exemplo conceitual:
INREC IFTHEN=(WHEN=GROUP,
BEGIN=(1,1,CH,EQ,C'H'),
PUSH=(81:ID=4))
Cada grupo recebe uma identificação.
Recursos de WHEN=GROUP são extremamente poderosos para arquivos hierárquicos, mas precisam ser testados com:
grupo sem trailer;
detalhe sem header;
dois headers consecutivos;
grupo vazio;
último grupo incompleto.
33. Preservando header e trailer com ICETOOL DATASORT
Às vezes o arquivo possui:
HEADER
DADOS
DADOS
DADOS
TRAILER
Queremos ordenar apenas os dados, mantendo o header no início e o trailer no final.
O operador DATASORT do ICETOOL foi criado justamente para classificar os registros de dados preservando registros de cabeçalho e rodapé. A IBM informa que esse operador usa EQUALS para manter a ordem relativa dos duplicados. (IBM)
Exemplo:
//TOOL EXEC PGM=ICETOOL
//TOOLMSG DD SYSOUT=*
//DFSMSG DD SYSOUT=*
//IN DD DSN=VAGNER.ARQUIVO.COMPLETO,DISP=SHR
//OUT DD DSN=VAGNER.ARQUIVO.ORDENADO,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(10,5),RLSE)
//TOOLIN DD *
DATASORT FROM(IN) TO(OUT) HEADER TRAILER USING(CTL1)
/*
//CTL1CNTL DD *
SORT FIELDS=(1,10,CH,A)
/*
34. ICETOOL: o canivete de campanha
ICETOOL é um utilitário multifuncional baseado nas capacidades do DFSORT e capaz de executar múltiplas operações em um único passo. (IBM)
O JCL básico:
//TOOL EXEC PGM=ICETOOL
//TOOLMSG DD SYSOUT=*
//DFSMSG DD SYSOUT=*
//ENTRADA DD DSN=VAGNER.ARQUIVO,DISP=SHR
//TOOLIN DD *
...
/*
Operadores comuns
COPY
Copia dados.
SORT
Classifica dados.
COUNT
Conta registros.
SELECT
Seleciona registros por ocorrência de chave.
UNIQUE
Mostra chaves únicas ou conta ocorrências, conforme construção utilizada.
OCCUR
Produz estatísticas de ocorrência.
DISPLAY
Gera relatórios formatados.
VERIFY
Verifica campos numéricos.
STATS
Produz estatísticas de campos numéricos.
RANGE
Seleciona valores dentro ou fora de intervalos.
SUBSET
Seleciona partes do arquivo.
DATASORT
Ordena dados preservando headers e trailers.
35. Contando registros com ICETOOL
//TOOL EXEC PGM=ICETOOL
//TOOLMSG DD SYSOUT=*
//DFSMSG DD SYSOUT=*
//ENTRADA DD DSN=VAGNER.CLIENTES,DISP=SHR
//TOOLIN DD *
COUNT FROM(ENTRADA)
/*
Também podemos testar condições.
Exemplo conceitual:
COUNT FROM(ENTRADA) EMPTY RC8
Se o arquivo estiver vazio, retorna RC 8.
Isso permite controlar passos posteriores com JCL:
//PROXIMO IF (TOOL.RC = 0) THEN
...
// ENDIF
Os return codes do ICETOOL podem representar tanto erros quanto condições programadas por operadores como COUNT. (IBM)
36. Selecionando duplicados com ICETOOL
Suponha que a conta esteja em 1–10.
Para selecionar chaves que aparecem mais de uma vez:
//TOOL EXEC PGM=ICETOOL
//TOOLMSG DD SYSOUT=*
//DFSMSG DD SYSOUT=*
//IN DD DSN=VAGNER.CONTAS,DISP=SHR
//DUP DD DSN=VAGNER.CONTAS.DUPLICADAS,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(5,2),RLSE)
//TOOLIN DD *
SELECT FROM(IN) TO(DUP) ON(1,10,CH) ALLDUPS
/*
Outras possibilidades podem selecionar:
primeira ocorrência;
última ocorrência;
valores que aparecem exatamente
nvezes;valores acima ou abaixo de determinada frequência;
registros únicos.
O operador SELECT utiliza classificação e pode preservar a ordem dos duplicados por meio de EQUALS. (IBM)
37. Validando campos numéricos
Antes de somar um campo packed ou zoned, convém verificar se os dados são válidos.
Um byte inválido pode derrubar a operação ou produzir resultado incorreto.
Com ICETOOL, pode-se utilizar VERIFY.
Exemplo conceitual:
VERIFY FROM(IN) ON(45,6,PD)
Essa é uma excelente missão preventiva antes de processar arquivos vindos de:
plataformas distribuídas;
conversões ASCII/EBCDIC;
uploads manuais;
arquivos construídos por scripts;
parceiros externos;
layouts alterados sem controle.
38. Ordenando datas
Data no formato AAAAMMDD
Se o campo possui:
20260730
20251201
20270115
pode ser ordenado como CH ou ZD, desde que esteja consistentemente preenchido:
SORT FIELDS=(1,8,CH,A)
O formato AAAAMMDD foi praticamente feito para ordenação lexicográfica.
Data DDMMYYYY
Considere:
30122025
01012026
15072024
Ordenar diretamente como texto não produz ordem cronológica.
Podemos ordenar por:
ano;
mês;
dia.
SORT FIELDS=(5,4,CH,A,
3,2,CH,A,
1,2,CH,A)
Ou criar uma chave temporária com INREC.
INREC BUILD=(5,4,
3,2,
1,2,
1,80)
SORT FIELDS=(1,8,CH,A)
OUTREC BUILD=(9,80)
A chave AAAAMMDD é acrescentada antes do registro, utilizada no SORT e removida na saída.
Esse truque é um clássico.
39. Ordenação case-insensitive
Em EBCDIC, letras maiúsculas e minúsculas possuem valores diferentes.
Uma lista com:
ANA
Ana
ana
BRUNO
Bruno
pode não ficar na ordem humana esperada.
Uma abordagem é criar uma chave temporária convertida para maiúsculas, ordenar por ela e depois remover a chave.
Exemplo conceitual:
INREC BUILD=(1,30,TRAN=LTOU,
1,100)
SORT FIELDS=(1,30,CH,A)
OUTREC BUILD=(31,100)
TRAN=LTOU transforma letras minúsculas em maiúsculas na chave de trabalho.
40. Concatenando vários arquivos de entrada
É possível concatenar datasets no SORTIN:
//SORTIN DD DSN=VAGNER.ARQ.JANEIRO,DISP=SHR
// DD DSN=VAGNER.ARQ.FEVEREIRO,DISP=SHR
// DD DSN=VAGNER.ARQ.MARCO,DISP=SHR
O SORT enxerga a concatenação como um fluxo de entrada.
Mas os datasets precisam ser compatíveis:
organização adequada;
atributos compatíveis;
layouts coerentes;
interpretação correta do registro.
Não concatene arquivos apenas porque possuem o mesmo LRECL.
Dois arquivos de 100 bytes podem ter layouts completamente diferentes.
41. Usando GDG
SORT e GDG formam uma dupla clássica.
//SORTIN DD DSN=VAGNER.MOVIMENTO.DIARIO(0),DISP=SHR
//SORTOUT DD DSN=VAGNER.MOVIMENTO.ORDENADO(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(20,10),RLSE),
// UNIT=SYSDA
Cuidados:
(0)refere-se normalmente à geração atual catalogada;(+1)cria uma nova geração;confirme o momento de catalogação;
lembre-se de que referências relativas podem assumir significado diferente conforme novas gerações são criadas no mesmo job.
Em jobs complexos, utilizar o mesmo (+1) em passos posteriores exige conhecimento preciso das regras de resolução do GDG.
42. Usando SORT com VSAM
DFSORT pode trabalhar com diferentes tipos de entrada e saída, inclusive VSAM em cenários suportados.
Mas o recruta deve tomar cuidado com:
organização do cluster;
chave VSAM;
REUSE;abertura para entrada e saída;
tentativa de usar o mesmo cluster simultaneamente;
tamanho máximo e médio do registro;
arquivos variáveis;
códigos de retorno;
necessidade de descarregar e recarregar o cluster.
A própria documentação alerta que determinadas combinações de mesmo dataset VSAM como entrada e saída exigem condições específicas; caso contrário, o DFSORT encerra a operação. (IBM)
Em muitos processos, é mais seguro:
descarregar;
transformar;
validar;
carregar em novo cluster;
trocar nomes ou executar procedimento controlado de substituição.
43. Return codes: o boletim da missão
Os códigos exatos devem ser confirmados pelas mensagens do produto e pelos padrões da instalação.
Como regra prática:
RC 0
Operação concluída normalmente.
RC 4
Aviso ou condição não fatal.
Pode indicar, por exemplo:
situação informativa;
condição programada;
comportamento que exige atenção.
RC 8 ou superior
Normalmente indica falha ou condição relevante.
Mas nunca interprete apenas o número.
Leia as mensagens:
ICE...
A mensagem detalhada é mais importante que o return code isolado.
O return code diz que alguém caiu. A mensagem diz onde estava a emboscada.
44. Erros clássicos do recruta
44.1 Posição errada
SORT FIELDS=(10,5,CH,A)
Mas o campo realmente começa em 11.
44.2 Esquecer o RDW em arquivo VB
Usa posição 1 quando deveria considerar a posição 5.
44.3 Tratar packed como texto
SORT FIELDS=(45,6,CH,A)
quando deveria ser:
SORT FIELDS=(45,6,PD,A)
44.4 Confundir tamanho lógico com tamanho físico
PIC S9(9)V99 COMP-3 não ocupa 11 bytes.
44.5 Usar posição original após INREC
O INREC muda o mapa do terreno.
44.6 Usar posição reformada antes do momento correto
Cada comando enxerga o registro em uma etapa específica.
44.7 Eliminar duplicados sem definir qual registro manter
SUM FIELDS=NONE não conhece a regra de negócio.
44.8 Sortear um arquivo que já estava ordenado
Talvez MERGE, COPY ou nenhuma operação fosse necessária.
44.9 Criar cinco passos quando um OUTFIL bastava
Mais passos significam:
mais I/O;
mais datasets;
mais pontos de falha;
mais JCL;
mais dificuldade de restart.
44.10 Esquecer registros vazios ou curtos em VB
Campos além do tamanho efetivo do registro podem causar problemas.
44.11 Confiar na ordem visual
Dados exibidos no ISPF podem esconder:
bytes não imprimíveis;
sinais packed;
zeros;
caracteres especiais;
diferenças entre espaço e low-value.
44.12 Ignorar a codificação
ASCII e EBCDIC não possuem a mesma sequência de caracteres.
45. Método passo a passo para escrever um SORT seguro
Passo 1 — Defina a missão
Escreva em português claro:
“Ler o arquivo de movimentos, selecionar transações aprovadas, ordenar por agência e conta, consolidar valores e produzir arquivos separados por região.”
Se você não consegue explicar a missão, ainda não está pronto para escrever o SYSIN.
Passo 2 — Obtenha o layout
Consulte:
copybook;
documentação;
amostra;
atributos do dataset;
origem do arquivo.
Passo 3 — Faça uma tabela de posições
| Campo | Início | Tamanho | Formato |
|---|---|---|---|
| Agência | 1 | 4 | CH |
| Conta | 5 | 10 | CH |
| Data | 15 | 8 | CH |
| Valor | 23 | 6 | PD |
| Status | 29 | 1 | CH |
Passo 4 — Examine dados reais
Use:
ISPF Browse;
modo hexadecimal;
File-AID ou ferramenta equivalente;
pequeno unload;
ICETOOL
DISPLAY;programa de diagnóstico.
Passo 5 — Faça primeiro uma amostra
Não comece testando com 500 milhões de registros.
Crie um dataset pequeno contendo:
menor chave;
maior chave;
duplicados;
valor zero;
valor negativo;
registro inválido;
status desconhecido;
primeiro e último grupo;
caracteres especiais.
Passo 6 — Escreva a operação mínima
Comece:
SORT FIELDS=COPY
Depois acrescente:
INCLUDE
INREC
SORT
SUM
OUTREC
OUTFIL
uma camada por vez.
Passo 7 — Valide contagens
Compare:
LIDOS
- DESCARTADOS
= GRAVADOS
Em múltiplas saídas:
ATIVOS + INATIVOS + CANCELADOS + REJEITADOS
= TOTAL DE ENTRADA
Passo 8 — Confirme a ordem
Verifique:
primeira chave;
última chave;
transição entre grupos;
duplicados;
chaves negativas ou especiais;
dados nulos ou espaços.
Passo 9 — Leia todas as mensagens
Não aceite apenas “RC=0”.
Veja:
opções usadas;
quantidade de registros;
alocação;
avisos;
mensagens de performance;
possíveis overrides da instalação.
As opções padrão podem ser alteradas pelos administradores do ambiente, portanto dois sistemas podem executar o mesmo JCL com defaults diferentes. (IBM)
Passo 10 — Documente a regra
Inclua comentários:
//* ORDENA MOVIMENTOS POR AGENCIA, CONTA E DATA
//* MANTEM O MOVIMENTO MAIS RECENTE POR CONTA
//* CAMPO DATA: POS 15, 8 BYTES, AAAAMMDD
O comentário de hoje é o mapa que salvará o recruta de amanhã.
46. Exemplo completo de produção
Missão
Ler movimentos bancários com layout FB de 80 bytes:
| Campo | Posição | Tamanho | Formato |
|---|---|---|---|
| Agência | 1 | 4 | CH |
| Conta | 5 | 10 | CH |
| Data | 15 | 8 | CH |
| Hora | 23 | 6 | CH |
| Tipo | 29 | 1 | CH |
| Valor | 30 | 6 | PD |
| Status | 36 | 1 | CH |
| Restante | 37 | 44 | CH |
Requisitos:
aceitar apenas status
A;ordenar por agência e conta;
dentro da conta, colocar data e hora mais recentes primeiro;
criar saída de crédito;
criar saída de débito;
criar saída para tipos desconhecidos;
adicionar data de processamento;
produzir contagem no rodapé.
//MOVSORT JOB (ACCT),'BELLACOSA',
// CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID
//*
//* PLATOON DO BATCH - CLASSIFICACAO DE MOVIMENTOS
//*
//ORDENA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=VAGNER.MOVIMENTO.BRUTO,DISP=SHR
//*
//CREDITO DD DSN=VAGNER.MOVIMENTO.CREDITO,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(50,20),RLSE),
// DCB=(RECFM=FB,LRECL=110,BLKSIZE=0)
//*
//DEBITO DD DSN=VAGNER.MOVIMENTO.DEBITO,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(50,20),RLSE),
// DCB=(RECFM=FB,LRECL=110,BLKSIZE=0)
//*
//REJEITA DD DSN=VAGNER.MOVIMENTO.REJEITADO,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(10,5),RLSE),
// DCB=(RECFM=FB,LRECL=110,BLKSIZE=0)
//*
//SYSIN DD *
INCLUDE COND=(36,1,CH,EQ,C'A')
SORT FIELDS=(1,4,CH,A,
5,10,CH,A,
15,8,CH,D,
23,6,CH,D)
OUTREC BUILD=(1,80,
C' PROC=',
DATE1,
C' ',
TIME1)
OUTFIL FNAMES=CREDITO,
INCLUDE=(29,1,CH,EQ,C'C'),
TRAILER1=(C'TOTAL CREDITOS: ',COUNT)
OUTFIL FNAMES=DEBITO,
INCLUDE=(29,1,CH,EQ,C'D'),
TRAILER1=(C'TOTAL DEBITOS: ',COUNT)
OUTFIL FNAMES=REJEITA,
SAVE,
TRAILER1=(C'TOTAL REJEITADOS: ',COUNT)
/*
Este exemplo precisa ser adaptado aos padrões locais, especialmente:
sintaxe de data e hora desejada;
LRECLfinal;formato dos trailers;
atributos de saída;
regras de negócio;
quantidade estimada de espaço;
produto SORT instalado.
47. Exemplo com dataset temporário e restart lógico
Imagine um job em três etapas:
selecionar e normalizar;
cruzar com cadastro;
gerar relatórios.
//PREPARA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=VAGNER.TRANSACOES.BRUTAS,DISP=SHR
//SORTOUT DD DSN=&&NORMAL,
// DISP=(NEW,PASS),
// UNIT=SYSDA,
// SPACE=(CYL,(100,50)),
// DCB=(RECFM=FB,LRECL=60,BLKSIZE=0)
//SYSIN DD *
INCLUDE COND=(100,1,CH,EQ,C'A')
INREC BUILD=(1,10,
20,8,
50,6,
120,35,
C'N')
SORT FIELDS=(1,10,CH,A)
/*
//*
//CRUZA EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTJNF1 DD DSN=&&NORMAL,DISP=(OLD,DELETE)
//SORTJNF2 DD DSN=VAGNER.CLIENTES.MESTRE,DISP=SHR
//SORTOUT DD DSN=&&CRUZADO,
// DISP=(NEW,PASS),
// UNIT=SYSDA,
// SPACE=(CYL,(100,50)),
// DCB=(RECFM=FB,LRECL=120,BLKSIZE=0)
//SYSIN DD *
JOINKEYS FILE=F1,FIELDS=(1,10,A)
JOINKEYS FILE=F2,FIELDS=(1,10,A)
JOIN UNPAIRED,F1
REFORMAT FIELDS=(F1:1,60,
F2:11,59,
?)
SORT FIELDS=COPY
/*
//*
//RELAT EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=&&CRUZADO,DISP=(OLD,DELETE)
//OK DD DSN=VAGNER.RELATORIO.OK,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(20,10),RLSE)
//SEMCLI DD DSN=VAGNER.RELATORIO.SEMCLIENTE,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,
// SPACE=(CYL,(10,5),RLSE)
//SYSIN DD *
SORT FIELDS=COPY
OUTFIL FNAMES=OK,
INCLUDE=(120,1,CH,EQ,C'B')
OUTFIL FNAMES=SEMCLI,
SAVE
/*
Nesse tipo de fluxo, os temporários fazem sentido porque representam fronteiras claras entre etapas diferentes.
Entretanto, se restart for requisito crítico, um dataset permanente controlado por geração ou ciclo pode ser preferível. Datasets &&TEMP desaparecem ao final do job e podem não servir como checkpoint reutilizável em uma nova submissão.
48. Curiosidades do acampamento
Curiosidade 1 — O SORT pode substituir pequenos programas COBOL
Muitos programas escritos apenas para:
filtrar;
mover campos;
somar;
eliminar duplicados;
separar arquivos;
inserir constantes;
poderiam ser substituídos por DFSORT.
Isso não significa que todo programa deve virar SORT.
Mas antes de criar um novo módulo COBOL, pergunte:
Esta lógica é transformação de registros ou verdadeira regra de negócio?
Curiosidade 2 — Um SORT bem escrito pode reduzir janelas batch
Eliminar leituras, escritas e passos intermediários pode representar grande economia em ambientes de alto volume.
Curiosidade 3 — “Arquivo já ordenado” é uma afirmação perigosa
Um arquivo pode estar:
visualmente ordenado;
ordenado apenas pela primeira chave;
ordenado em ASCII, não EBCDIC;
ordenado crescentemente quando o programa espera decrescente;
ordenado sem estabilidade;
ordenado antes de uma concatenação desordenada.
Curiosidade 4 — A menor mudança no layout pode destruir o resultado
Adicionar dois bytes no início do arquivo desloca todas as posições posteriores.
O SORT continuará executando.
Talvez retorne RC 0.
E produzirá dados perfeitamente classificados pela coluna errada.
Esse é um dos cenários mais perigosos: o erro silencioso.
Curiosidade 5 — O nome ICETOOL combina com o produto
Enquanto o CPD esquenta, o ICETOOL entra em cena com seus comandos começando por ICE.
Curiosidade 6 — Nem todo RC 4 é derrota
Às vezes é uma condição planejada para controlar o fluxo do job.
Curiosidade 7 — O SORT conhece o registro em diferentes versões
O registro visto por INCLUDE pode não ser o mesmo visto por SORT, que pode não ser o mesmo visto por OUTFIL.
Compreender a ordem de processamento é metade do treinamento.
49. Easter eggs Bellacosa
Easter egg 1 — O sargento Elias dos datasets
INCLUDE é o soldado que olha cada registro e decide:
— Você vem conosco.
OMIT olha o mesmo registro e diz:
— Você fica.
Easter egg 2 — O sargento Barnes do batch
SUM FIELDS=NONE não negocia com duplicados.
Ele escolhe um sobrevivente e remove os demais.
Por isso, nunca o deixe decidir sozinho quando a regra de negócio exige saber exatamente qual registro deve permanecer.
Easter egg 3 — A floresta não é o que parece
No arquivo VB, os quatro bytes do RDW estão sempre à frente.
Invisíveis.
Esperando o recruta esquecer que eles existem.
Easter egg 4 — “Adagio for Strings” no CPD
Quando o job termina com RC 16 às cinco e cinquenta da manhã e a janela batch fecha às seis, algum operador deveria colocar Adagio for Strings para tocar no data center.
Easter egg 5 — Ninguém luta sozinho
O SORT prepara dados para:
COBOL;
CICS;
Db2;
IMS;
VSAM;
relatórios;
reconciliações;
fechamento contábil;
processamento de cartões;
folhas de pagamento.
Ele raramente recebe aplausos.
Mas, quando falha, todo o exército percebe.
50. Checklist do recruta antes de liberar o JCL
Dataset
Confirmei
RECFM.Confirmei
LRECL.Confirmei se o arquivo é FB ou VB.
Confirmei se há RDW.
Confirmei organização e volume.
Confirmei se a entrada pode estar vazia.
Layout
Calculei as posições.
Verifiquei campos packed.
Verifiquei campos binários.
Examinei dados em hexadecimal.
Confirmei sinais e decimais implícitos.
Regras
Sei quais registros entram.
Sei quais registros são eliminados.
Sei como duplicados devem ser tratados.
Sei qual registro deve sobreviver.
Sei a ordem exata das chaves.
Sei quais saídas serão produzidas.
Performance
Filtrei antes de ordenar.
Reduzi registros quando possível.
Evitei passos redundantes.
Avaliei
OUTFIL.Avaliei
MERGE.Não copiei
SORTWKnnsem justificativa.Estimei espaço de saída.
Validação
Testei arquivo vazio.
Testei um registro.
Testei duplicados.
Testei valores negativos.
Testei chave mínima e máxima.
Conferi contagens.
Conferi primeiro e último registro.
Li as mensagens completas.
Documentei as posições.
51. Dez comandos que todo recruta deve memorizar
//* 1. ORDENAR
SORT FIELDS=(1,10,CH,A)
//* 2. COPIAR
SORT FIELDS=COPY
//* 3. INCLUIR
INCLUDE COND=(20,1,CH,EQ,C'A')
//* 4. OMITIR
OMIT COND=(20,1,CH,EQ,C'C')
//* 5. REMOVER DUPLICADOS
SORT FIELDS=(1,10,CH,A)
SUM FIELDS=NONE
//* 6. SOMAR
SORT FIELDS=(1,4,CH,A)
SUM FIELDS=(20,6,PD)
//* 7. REFORMATAR ANTES
INREC BUILD=(10,5,1,9)
//* 8. REFORMATAR DEPOIS
OUTREC BUILD=(1,10,C'|',11,20)
//* 9. MULTIPLAS SAIDAS
OUTFIL FNAMES=SAIDA1,INCLUDE=(1,1,CH,EQ,C'A')
OUTFIL FNAMES=SAIDA2,SAVE
//* 10. CRUZAR ARQUIVOS
JOINKEYS FILE=F1,FIELDS=(1,10,A)
JOINKEYS FILE=F2,FIELDS=(1,10,A)
52. A última lição do pelotão
O recruta submeteu o job às cinco e doze.
O JES aceitou.
O passo iniciou.
Milhões de registros entraram no DFSORT como soldados perdidos em uma floresta fechada. Contas, agências, datas e valores atravessaram memória, buffers e áreas de trabalho.
Alguns registros foram eliminados.
Outros foram reformatados.
Duplicados desapareceram.
Valores foram consolidados.
Três arquivos surgiram na saída, cada um rigorosamente organizado.
Às cinco e vinte e nove, o job terminou:
MAXCC=0000
O veterano examinou as mensagens, conferiu as contagens e perguntou:
— Quantos registros entraram?
O recruta respondeu.
— Quantos foram rejeitados?
O recruta respondeu novamente.
— Qual duplicado foi mantido?
Dessa vez, o jovem mostrou a regra de data e hora descendente.
O veterano finalmente assentiu.
Não porque o job havia terminado com RC 0.
Mas porque o recruta sabia explicar por que o resultado estava correto.
No mainframe, qualquer um pode copiar uma instrução:
SORT FIELDS=(1,10,CH,A)
O verdadeiro profissional entende:
quais bytes estão sendo comparados;
como estão representados;
em que momento o registro foi transformado;
quanto espaço será utilizado;
qual duplicado sobreviverá;
o que acontecerá quando o arquivo estiver vazio;
como provar que a saída está certa.
Essa é a diferença entre executar um SORT e comandar o SORT.
E quando a madrugada cair sobre o CPD, os discos começarem a girar e milhões de registros marcharem para dentro do batch, lembre-se:
O caos pode ter milhões de linhas.
Mas basta uma chave correta para colocá-lo em ordem.
Bem-vindo ao pelotão, recruta.
Sem comentários:
Enviar um comentário