Sei sulla pagina 1di 80

Programação SQL com SIGA Advanced / AP5

Programação SQL (Intermediário)

Com SigaAdvanced/ AP5

Windows NT Server , Windows Workstation, Windows 95/98 e SQL Server são marcas
registradas da Microsoft Corporation.
Banco de Dados Oracle é a marca registrada da Oracle Corporation.
Banco de Dados Informix é a marca registrada da Informix Corporation.
Banco de Dados Sybase é a marca registrada da Sybase Corporation.
Banco de Dados UDB é a marca registrada da IBM.
Programação SQL com SIGA Advanced / AP5

Este material é de efeito didático/suporte e não pode ser reproduzido sem autorização da
MicroSiga.
CopyRight © 2000 Microsiga Software S.A.

Índice
1. Introdução ao ambiente Relacional
1.1. Objetivos
1.2. Conceitos Básicos de Banco de Dados
1.3. Conhecendo a estrutura de Armazenamento dos dados
1.3.1. LOG do Banco de dados
1.3.1.1. Controle Transacional
1.3.1.2. Segurança e Backup
1.3.1.3. Construindo Query’s evitando problemas com estouro da Área de
LOG
1.3.2. Área temporária do Banco de Dados
1.4. Normalização de Base de Dados
1.5. MER (Modelo Entidade Relacionamento)
1.6. Diferenças cruciais entre ambientes DBF e SQL
1.6.1. DBF – Trabalha de forma posicional com acesso compartilhado
1.6.2. SQL – Trabalha de forma relacional (Teoria dos conjuntos) e o acesso é de
forma centralizada

2. TopConnect
2.1. Informações gerais
2.2. Controle de tipo de dados ( Tabela TOP_FIELD )
2.3. Opções de Visualizar os Eventos (Mensagens de Erros)
2.4. Sistema de controle de Registros
2.4.1. Portabilidade
2.4.2. Função da coluna R_E_C_N_O_
2.4.2.1. Limite de registros
2.4.2.2. Renumeração da coluna RECNO
2.4.3. Controle dos registros deletados (Coluna D_E_L_E_T_)
2.5. Constraints do Banco de dados que são criados automaticamente
2.5.1. Criação da Estrutura de tabelas
2.5.2. Índices
2.5.3. Defaults
2.5.4. Problemas com conteúdo Nulo
2.6. Manutenção do Banco de dados
2.6.1. Aumentando a performance executando a operação de PACK
2.7. DBFNTX x TopConnect
2.7.1. Índices de produção
2.7.2. Funções em chaves de índices
2.7.3. Índices condicionais
2.7.4. Chaves numéricas compostas
2.7.5. Expressões de filtro com funções e variáveis
2.8. Comandos
2.8.1. APPEND FROM
2.8.2. COPY TO
2.8.3. USE
2.8.4. BEGIN, COMMIT, ROLLBACK TRANSACTION
Programação SQL com SIGA Advanced / AP5

2.9. Funções
2.9.1. TCCANOPEN
2.9.2. TCCONTYPE
2.9.3. TCDELFILE
2.9.4. TCGETDB
2.9.5. TCLINK
2.9.6. TCQUERY
2.9.7. TCQUIT
2.9.8. TCSETCONN
2.9.9. TCSETFIELD
2.9.10. TCSPEXEC
2.9.11. TCSPEXIST
2.9.12. TCSQLERROR
2.9.13. TCSQLEXEC
2.9.14. TCSRVTYPE
2.9.15. TCUNLINK
2.9.16. TCCHKOBJ*
2.9.17. TCEXEERROR*
2.9.18. TCPGMEXE*
2.9.19. TCSYSEXE*
( * )Funções apenas para o TOPConnect rodando em servidores AS/400.

2.10. Performance
2.10.1. Otimizando seu código
2.10.2. Leitura Sequencial
2.10.3. O uso de filtros
2.10.4. Stored Procedures
2.11. Integração com outros aplicativos
2.11.1. Incluindo registros nas tabelas do SigaAdvanced / AP5
2.11.2. Excluindo registros ( Sempre Marcar )
2.11.3. Vantagens e Desvantagens

3. Utilitário importante
3.1. Instalador de Stored Procedures no Banco de Dados
Programação SQL com SIGA Advanced / AP5

1. Introdução ao ambiente Relacional


1.1. Objetivos

Este curso tem como objetivo treinar e aperfeiçoar nossos analistas e parceiros quanto à
confecção de programas específicos, em ambiente de trabalho com Base de Dados SQL
desta forma pretendemos aumentar a facilidade de manuseio dos componentes
envolvidos tanto na análise e detecção de erros, e quais possíveis ações para saná-los,
antes de recorrer ao suporte interno. Demonstraremos também como otimizar programas
através da linguagem SQL em seus RDMAKES e futuras implementações para as
próximas versões.
Todos os tópicos mencionados poderão servir como base de consulta, para escrita de
programas e resolução de problemas.

1.2. Conceitos Básicos de Banco de Dados

Os conceitos básicos dos Bancos de Dados relacionais são bem diferenciados dos
conhecidos DBF´s. Estes conceitos básicos são úteis principalmente para saber
responder eventuais perguntas que nossos clientes poderão efetuar sobre nosso
sistema.

SQL quer dizer : Structured Query Language , que foi desenvolvido inicialmente pela
IBM Corporation.

Um banco de dados não trabalha em função de registros, ou Arquivos como nós


estamos acostumados a ver e fazer em linguagem de programação Clipper. o SQL
utiliza a teoria de conjuntos conhecida pôr todos, que tem o objetivo de resolver os
problemas dos usuários com comandos simples, chamados de query´s ( Requisição e
Alteração de dados ), que utilizam basicamente 4 comandos : SELECT, INSERT,
UPDATE, DELETE.

A primeira diferença entre o ambiente SQL e o DBF é o fato de criarmos uma área no
disco (DATABASE) que o próprio banco se encarregara de administrar, no sentido de
criar tabelas, índices, e todos os objetos envolvidos no sistema. A nomenclatura muda
um pouco: ao invés de CAMPOS temos COLUNAS e ao invés de REGISTROS temos
LINHAS.

Os índices trabalham de forma semelhante ao DBF, e são utilizados com duas


finalidades : a de termos uma chave de acesso extremamente rápida, e de garantirmos
uma chave única em uma tabela. A partir do momento que indicamos uma chave única
em uma tabela, o próprio banco de dados passa a garantir que não existirá dados
duplicados, sem a necessidade de programação para tal.

Também estarão ligados à uma tabela específica os Triggers, e as Foreign Keys


( Chaves Estrangeiras ). Em cada DataBase também estarão armazenadas as Stored
Procedures, que são programas ou funções escritas como qualquer linguagem
conhecida ( Clipper, Pascal etc.), só que no padrão ANSI / SQL.

Uma Trigger funciona como um gatilho, só que este é disparado não a cada campo
alterado, e sim a cada Inclusão, Alteração ou Exclusão de uma linha da tabela. Os
Triggers também são escritos como as Stored Procedures, ou seja, como um
programa qualquer, que pode efetuar qualquer tipo de validação, atualização em outras
tabelas, etc...
Hoje não utilizamos no Siga Advanced nenhuma Trigger. Em alguns casos específicos
em clientes, as mesmas poderão ser utilizadas.
Programação SQL com SIGA Advanced / AP5

Uma Foreign Key ( Chave Estrangeira ) é uma ligação entre tabelas que são criadas
nas mesmas. São estas que garantem que nunca o Cliente “X” será excluído se o
mesmo tiver movimentos ( Pedidos, Notas , Duplicatas Etc. ), também será garantido
que nunca será incluído um Pedido de Vendas do Cliente “Y”, se o mesmo não existir.
Este tratamento é feito diretamente pelo Banco de Dados, não necessitando qualquer
codificação para isto.

O Siga Advanced/AP5 não trabalha hoje com o conceito de chaves estrangeiras no


banco de dados.

O uso de um Banco de Dados SQL se faz necessário pela segurança dos dados e pela
fácil recuperação dos mesmos por vários aplicativos como Siga Advanced / AP5
(TopConnect), Crystal Reports (ODBC), SigaEIS (BDE), Excel, etc.

Devido ao controle exercido sobre os dados a performance do banco acaba sendo


prejudicada. Nos próximos tópicos estaremos demonstrando como melhorar e otimizar
o SGDB (Sistema Gerenciador de Banco de Dados) para o melhor aproveitamento do
sistema.

Para empresas que fazem uma grande utilização de banco de dados normalmente
encontramos um profissional chamado DBA (Data Base Administrator), que tem a
função de administrar o banco de dados, quanto a otimização, configuração, backups e
segurança. Sabemos que na prática isto só funciona para empresas grandes, portanto
temos que saber o mínimo possível de cada banco de dados para podermos identificar
problemas e soluções que se adequam melhor à instalação do cliente.
Programação SQL com SIGA Advanced / AP5

1.3. Conhecendo a estrutura de Armazenamento dos dados

1.3.1. LOG do Banco de dados

1.3.1.1. Controle Transacional

Toda e qualquer operação de inclusão, alteração ou exclusão de registro é


armazenada primeiramente na área de LOG. Se você faz uma inclusão no
banco de dados de uma simples linha o mesmo garante a inclusão completa
da linha (inserção de todas as colunas). Este fato é garantido pela definição no
seu banco de dados de uma transação implicita. Agora vamos supor que você
tenha uma operação que necessite que várias inclusões, alterações e
exclusões realizadas só sejam efetuadas quando todas as operações tenham
sido efetuadas com sucesso, caso contrário todas as operações devem ser
canceladas.

Para definição de transação pelo usuário, normalmente se utilizam os


comandos BEGIN e COMMIT , para definir início e fim de uma transação
respectivamente. Para o cancelamento de um transação sem sucesso
normalmente chamamos de ROLLBACK.

A área de LOG do Banco de dados é normalmente definida com 25% do


tamanho da área de dados, mas este fator depende muito do número de
usuários e a quantidade de transações realizadas em um determinado
intervalo de tempo.

1.3.1.2. Segurança e Backup

Depois que uma transação é concluída com sucesso, não indica que a mesma
estará sendo transferida para a área real dos dados. Este tramite de
transferência é chamado de CheckPoint , este ponto é configuravél de acordo o
SGDB utilizado. Para bancos de dados de maior escala, o processo de check
point só é realizado após o Backup da área de LOG.

O LOG também é utilizado para fazer o backup de grande bancos de dados,


guardando somente as alterações efetuados em um determinado intervalo de
Programação SQL com SIGA Advanced / AP5

tempo. Em clientes com base de dados pequenas, não utilizamos este tipo de
recurso.

1.3.1.3. Construindo Query’s evitando problemas com estouro da Área de


LOG

Conhecendo melhor o processo de gravação do banco de dados, percebemos


que quanto menor for o número de operações de inserção, alteração e exclusão
realizados dentro de uma transação melhor será a performance. Banco de dados
que possuem grandes transações ocasionam problemas de deadlock. Realização
de grandes updates na base de dados sem informar a clausula Where
delimitando um intervalo de linhas a serem modificados. Na alteração e exclusão
de linhas, precisamos tomar cuidado sempre com o intervalo de registros, se for
o caso devemos executar várias vezes o mesmo blocos de comandos, mudando
o intervalo de linhas, deste forma nunca teremos problemas com a área de LOG.

1.3.2. Área temporária do Banco de Dados

Esta área é de utilidade exclusiva do Banco de Dados, a mesma é utilizada em


situações que o SGDB precisa gerar arquivo temporários para resolver as query’s
que estamos solicitando, normalmente operações que exigem um determinada
ordenação no resultado e não existe nenhum índice correspondente. Devemos
tomar cuidado com query’s que necessitem área de trabalho, por que elas estarão
perdendo mais tempo com i/o de disco.
Programação SQL com SIGA Advanced / AP5

1.4. Normalização de Base de Dados

A normalização de Base de dados tem como objetivo, definir a estrutura de entidades e


seus atributos eliminando vários problemas de definição de armazenamento dos dados,
que no momento da implementação serão percebidos. Existe até cinco níveis de
normalização , mas somente utilizamos até o terceiro nível, atualmente não existe
equipamento capaz de administrar um Banco de dados normalizado totalmente.

Com a pratica vamos perceber que a normalização é muito boa, mas o seu excesso gera
problemas na programação, portanto temos sempre que fazer o máximo de normalização
mas devemos estar consciente de quanto conseguiremos de vantagem com isto.

Existe casos que a desnormalização é uma das melhores soluções, para facilitar o
desenvolvimento da aplicação ou para ganharmos performance.

A primeira forma normal diz que devemos definir a entidade e seus atributos, e destes
atributos devemos definir um atributo chave de relação.

Ex.: Entidade = Pedido


Atributos = Data Emissão, Produto , Quantidade ,etc.

Neste caso criaremos um campo código que define a sua chave principal de
relacionamento, criaremos o Código. Nunca utilize mais de um coluna agregada com
campo chave.(Este tipo de campo gera vários problemas na programação SQL)

A segunda forma normal diz que devemos subdividir os atributos que ocorrem mais de
que uma vez, em uma outra entidade.(Esta entidade deve ter um campo chave,
atendendo a primeira forma normal).

Ex.: Entidade = Pedido


Atributos = Número do Pedido (Chave), Data de Emissão, etc.

Entidade = Itens do Pedido


Atributos = Número, item (Número+item = chave), Quantidade, etc..

A terceira forma normal diz que devemos eliminar colunas que são concebidas por
calculo de outras colunas de mesma entidade.

Ex.: Entidade = Pedido


Atributos = Total do Pedido, Quantidade Total, etc.
Programação SQL com SIGA Advanced / AP5

1.5. MER (Modelo Entidade Relacionamento)

A partir da normalização podemos definir as relações estrangeiras de cada tabela, o MER


é uma modelo gráfico que facilita a visualização do desenvolvimento de aplicativo. Além
de apresentar todo o fluxo do dado dentro de um Banco de Dados. No caso do
SigaAdvanced / AP5 você ter em mãos toda a estrutura do sistema é quase impossível,
nestes casos o modelo é feito por módulo, e os pontos de integração são replicados em
cada MER do correspondente módulo.

Sempre que possível ao desenvolver processos específicos no sistema procure desenhar


o MER para detectar os problemas antes de sair desenvolvendo o produto.
Programação SQL com SIGA Advanced / AP5

1.6. Diferenças cruciais entre ambientes DBF e SQL


1.6.1. DBF – Trabalha de forma posicional com acesso compartilhado

Quando trabalhamos em um ambiente posicional, vários regras de programação e


definição como apresentamos acima, não precisam ser cumpridas. E mesmo assim
os processos são rápidos e de fácil manuseio. Este ambiente utiliza o modo
Shared de controle de arquivos do sistema operacional, ou seja, o servidor destes
arquivos é apenas um mero repositório de dados, nada é processado no Server. A
desvantagem de utilizar estes arquivos normalmente é taxada pelo problemas
gerados com erro em arquivos de índices e o nível de segurança muito baixo.

1.6.2. SQL – Trabalha de forma relacional (Teoria dos conjuntos) e o acesso é de


forma centralizada

Agora quando trabalhamos com Base de Dados Relacional, a estrutura é totalmente


diferente. Devemos atender várias exigências como controle de acesso ao dado que
é muito mais restrito, a programação feita na aplicação deve ser bem otimizada para
evitar requisições desnecessárias, o SGDB precisa utilizar processamento do
Servidor para recuperar um dado solicitado pela aplicação. O Banco de Dados
suporta grande capacidade de armazenamento de dados, garantindo sua integridade
como um todo. A desvantagem do Banco de Dados é a necessidade de
equipamentos potentes para atender a demanda.
Programação SQL com SIGA Advanced / AP5

2. TopConnect

2.1. Informações gerais

O TOPConnect foi desenvolvido em linguagem ‘C’ pela Microsiga e é utilizado hoje


pelo SigaAdvanced / AP5 através da linguagem ADVPL (Advanced Protheus
Language). Ele também pode ser utilizado por aplicações XBASE que queiram trocar a
base de dados de DBF para SQL.
Os gerenciadores de banco de dados hoje suportados são:

 MS-SQL Server 6.5 e 7.0 ( MSSQL / MSSQL7 )


 Oracle 7.3.4, 8.0.5 e 8i ( ORACLE )
 IBM Universal Database 5.0 ( DB2 )
 DB2/400 ( AS/400 )
 Sybase Anywhere ( ANYWHERE / ANYSYB )
 Sybase SQL-Server ( SYBASE )
 Informix ( INFORMIX )

O TOPConnect é composto por um biblioteca replaceble database driver(RDD) e


componentes de comunicação, sendo estes bibliotecas para aplicativos DOS e DLL's
para aplicativos Windows. Estas bibliotecas devem ser linkeditadas com sua aplicação
ADVPL para acessar o TOPConnect Server.

Alguns comandos e funções avançadas são disponibilizadas para que seu aplicativo
possa usufruir de todos os benefícios da plataforma cliente servidor, que são
apresentados logo em seguida.
Programação SQL com SIGA Advanced / AP5

2.2. Controle de tipo de dados ( Tabela TOP_FIELD )

Em um banco existem vários tipos de dados (CHAR, VARCHAR, FLOAT, NUMBER, etc.)
porem para existir uma unicidade no código do Topconnect alguns dados são
armazenados de forma diferente da definida na tabela SX3, porem a aplicação recebe o
dado da forma como definido.

Os tipos de dados que são tratados atualmente são o seguintes:

 Campos numéricos - são armazenados em variáveis do tipo FLOAT


 Campos Lógicos - são armazenados em variáveis do tipo CHAR (0 ou 1)
 Campos Data - são armazenados em variáveis do tipo CHAR com 8
bytes, no formato YYYYMMDD.

Os campo caracter não recebem nenhum tratamento.

A tabela TOP_FIELD contem a descrição de todos os campos NAO-CARACTER, para


que o TopConnect faca a conversão dos dados quando da leitura dos mesmos.
Ela é “alimentada” na criação de uma tabela.

Ex.: Tabela SA1010

A1_FILIAL C 2
A1_COD C 6
A1_LOJA C 2
A1_DESC C 1
A1_EMISSAO C 8
A1_VEND1 C 6
...
Ex.: Tabela TOP_FIELD

FIELD_TABLE FIELD_NAME FIELD_TYPE FIELD_PREC FIELD_DEC


------------------------------------------------------ -------------------------------- ------------------ ------------------ ----------------
dbo.SA1010 A1_COMIS P 5 2
dbo.SA1010 A1_DESC P 2 0
dbo.SA1010 A1_LC P 14 2
dbo.SA1010 A1_EMISSAO D 8 0
dbo.SA1010 A1_MCOMPRA P 17 2
dbo.SA1010 A1_METR P 7 2
dbo.SA1010 @@HAS_DFT_VAL@@ X 0 0
...
Neste exemplo vocês perceberão que na tabela TOP_FIELD só existe os campo
numéricos, data e Lógico (no caso não existe nenhum usado pelo arquivo).

Alerta! : Se você for utilizar diretamente o Banco de dados você precisa estar ciente que
um campo numérico é armazenado como um tipo float(MSSQL Server),
Number(Oracle), etc. Por exemplo o valor 40,40 no banco pode estar
armazenado como 40,39999999. Quando formos utilizar query’s você deve
utilizar a função TCSETFIELD para resolver esta situação.(Veja função
TCSETFIELD).
Importante também salientar que qualquer modificação efetuada em arquivo
SX3 diretamente, ou seja, sem utilizar o configurador, você pode Ter problemas
com inconsistência de estrutura da tabela do Banco de Dados e TOP_FIELD
contra o dicionário de dados. Para resolver este problema você deverá remover
os dados da Tabela do Banco de dados, eliminar a tabela e deixa-la criar
novamente e depois importar os dados via APPEND(Utilize SDU/CFG-AP5), ou
você pode ajustar o dicionário de dados manualmente conforme estrutura no
Banco de Dados.
Programação SQL com SIGA Advanced / AP5

2.3. Opções de Visualizar os Eventos (Mensagens de Erros)

A parte mais importante do Topconnect Manager é o gerenciamento das mensagens de


erros, estas mensagens não são do TopConnect mas sim, de cada Banco de Dados, ou
seja, se você obtiver um erro de Logon o erro que você receberá neste reporte, é
exatamente a mesma mensagem que o Banco de Dados estaria informando se você
utilizar um utilitário do próprio Banco para fazer o Acesso.

Na maioria dos problemas este logo de erros é o ponto principal para descobrir o que
esta acontecendo, entre o Topconnect e o Banco de dados. Você só estará recebendo
mensagens se o link entre o Banco de dados e o Topconnect estiver funcionando.

2.4. Sistema de controle de Registros


2.4.1. Portabilidade

Acreditamos que muitos já perguntarão por que da existência da coluna


R_E_C_N_O_ no Banco de dados, mesmo os que não conhecem esta coluna tem
como objetivo manter a portabilidade de uma Base DBF e Banco ADS para um
Banco de Dados qualquer e também entre Banco de dados. Se você possui sua
aplicação trabalhando em DBF , você pode porta-la independente de modificações
para uma Base SQL, e se você já esta em uma base SQL do tipo MSSQL SQL
Server e gostaria de porta-la para ORACLE, você pode fazer isto sem nenhum
problema.

Alerta! : Se você possui programas específicos desenvolvidos (RDMAKES), você


precisa que os mesmos estejam desenvolvidos nos padrões de compatibilidade
exigidos pela Microsiga. Você verá mais adiante exemplos de programas e uma
apresentação mais completa deste assunto.

2.4.2. Função da coluna R_E_C_N_O_

A Coluna R_E_C_N_O_, tem por objetivo principal guardar um número seqüencial


de controle de registro, mais conhecido como ID (identificador). Este identificador é
utilizado pela aplicação na pesquisa e posicionamento de registro.
Programação SQL com SIGA Advanced / AP5

Esta coluna não possui repetição, ela é sempre preenchida com o valor máximo da
coluna R_E_C_N_O_ + 1 nas próximas inserções. Esta operação é feita pelo
TopConnect , se você utiliza outros produtos que fazem inserção na Base de Dados
do Sigaadvanced / AP5 você deve seguir as orientações do Capítulo Integrações com
outros aplicativos.

2.4.2.1. Limite de registros

O limite de registros em uma tabela é de 2,147,483,648 , este número


normalmente deve ser levado em consideração para as tabelas que
recebem muita inserção de registro seguidas de muitas exclusões física do
registro.

2.4.2.2. Renumeração da coluna RECNO

Quando os registros são deletados pelo sistema, os mesmos são apenas


marcados, para exclusão física acontece em quando executamos a
operação que conhecemos com Pack de registros. Após esta operação a
coluna R_E_C_N_O_ não é renumerada. Não existe a necessidade de
fazer a renumeração desta coluna, a não ser que você esteja perto de
estourar o maior número possível nesta coluna. Neste caso você precisar
extrair os dados do Banco de Dados para uma Base DBF e logo em
seguida subir a Base novamente para o Banco de Dados,
automaticamente a coluna R_E_C_N_O_ será ajustada.

2.4.3. Controle dos registros deletados (Coluna D_E_L_E_T_)

Toda exclusão de registro feita no Banco de Dados ou em qualquer plataforma do


SigaAdvanced / AP5, só é feita logicamente, ou seja, o registro é marcado como
excluído (delete), e esta marca é feita utilizando o campo chamado D_E_L_E_T_ , a
mesma é preenchida com (*) Asterisco, caso contrário a coluna permanece com o
conteúdo em branco.

Alerta! : Quando você utiliza o comando Set Delet on/off, o TopConnect estará
tratando o dado para você, mas se você utiliza query’s para recuperação de dados
você deverá tratar este coluna (Mais informações sobre o tratamento da coluna
D_E_L_E_T_ será apresentado em exemplos de query’s em RDMAKES.
Programação SQL com SIGA Advanced / AP5

2.5. Constraints do Banco de dados que são criados automaticamente

2.5.1. Criação da Estrutura de tabelas

A estrutura de cada tabela do SigaAdvacend é criada automaticamente, tendo em


vista a não existência da mesma no Banco de Dados. Para isto o usuário criado
para o TopConnect acessar o banco de dados precisa Ter permissão de criação de
tabelas, de preferência a permissão de DBA.

Neste momento a tabela TOP_FIELD estará sendo alimentada com todos os


campos numéricos, datas e Lógicos.

Alerta! : Após o primeiro usuário fazer a conexão com o TopConnect e a parte de


verificação de tabelas já foi executada, as referências de cada tabela selecionado
no .mnu para abertura estarão em memória no TopConnect, portanto se por
acaso alguma tabela for removida diretamente por um utilitário do Banco de Dados
o TopConnect terá uma informação não coerente, você deve reiniciar o serviço do
Topconnect (Parando / iniciando o Serviço).

2.5.2. Índices

Os índices são criados imediatamente após a criação da estrutura das tabelas. Os


índices criados partem do arquivo de índices do SigaAdvanced / AP5, que é o
arquivo SINDEX. Existe um índice que é criado apenas uma vez no momento em
que a tabela é criada, este índice tem como formação do nome = <nome da
tabela> + _RECNO , este índice e sempre composto da coluna R_E_C_N_O_ e
não permite duplicidade.

Alerta!: Nunca remova os índices das tabelas, principalmente o índice RECNO


que não será criado pelo TopConnect quando a tabela já existe. Se você criou um
índice pelo SINDEX e depois percebeu que montou errado ou precisa elimina-lo,
você precisa eliminá-lo do SINDEX e também do Banco de Dados.

2.5.3. Defaults

São constraints de validação de campos que não são informados, nos comandos
de inserção e alteração, ou seja, se você não possui os defaults criados o Banco
de Dados estará deixando estes campos com valor nulo. Os defaults são criados
no momento da criação das tabelas.

Alerta!: Se você fizer qualquer operação de transferência via Banco de Dados que
não transfira os Defaults, e logo em seguida você utilizar o sistema , estará
correndo risco de inserir nulos na Base de Dados. Se isto acontecer você poderá
Ter problemas com o TopConnect Server, ele poderá travar ou derrubar conexões
com dados indevidos. A solução neste caso é utilizar o utilitário DEFAULT que
esta disponível no site da Microsiga.
Programação SQL com SIGA Advanced / AP5

Este é um exemplo de script para MSSQL Server que o TopConnect estará


disparando para o Banco de Dados quando a tabela SA1990 não existir no Banco.

CREATE TABLE [dbo].[SA1990] (


[A1_FILIAL] [varchar] (2) NULL ,
[A1_COD] [varchar] (6) NULL ,
[A1_LOJA] [varchar] (2) NULL ,
[A1_NOME] [varchar] (40) NULL ,
[A1_NREDUZ] [varchar] (20) NULL ,
[A1_TIPO] [varchar] (1) NULL ,
...
[D_E_L_E_T_] [varchar] (1) NULL ,
[R_E_C_N_O_] [int] NULL
)
GO

CREATE UNIQUE CLUSTERED INDEX [SA1990_RECNO] ON [dbo].[SA1990]([R_E_C_N_O_]) ON


[PRIMARY]
GO

ALTER TABLE [dbo].[SA1990] WITH NOCHECK ADD


CONSTRAINT [DF__SA1990__A1_FILIA__06648751] DEFAULT (' ') FOR [A1_FILIAL],
CONSTRAINT [DF__SA1990__A1_COD__0758AB8A] DEFAULT (' ') FOR [A1_COD],
CONSTRAINT [DF__SA1990__A1_LOJA__084CCFC3] DEFAULT (' ') FOR [A1_LOJA],
CONSTRAINT [DF__SA1990__A1_NOME__0940F3FC] DEFAULT (' ') FOR
[A1_NOME],
CONSTRAINT [DF__SA1990__A1_NREDU__0A351835] DEFAULT (' ') FOR
[A1_NREDUZ],
CONSTRAINT [DF__SA1990__A1_TIPO__0B293C6E] DEFAULT (' ') FOR [A1_TIPO],
...
CONSTRAINT [DF__SA1990__D_E_L_E___6E57F396] DEFAULT (' ') FOR [D_E_L_E_T_],
CONSTRAINT [DF__SA1990__R_E_C_N___6F4C17CF] DEFAULT (0) FOR [R_E_C_N_O_]
GO

CREATE INDEX [SA19901] ON [dbo].[SA1990]([A1_FILIAL], [A1_COD], [A1_LOJA], [R_E_C_N_O_]) ON


[PRIMARY]
GO

CREATE INDEX [SA19902] ON [dbo].[SA1990]([A1_FILIAL], [A1_NOME], [A1_LOJA], [R_E_C_N_O_]) ON


[PRIMARY]
GO

CREATE INDEX [SA19903] ON [dbo].[SA1990]([A1_FILIAL], [A1_CGC], [R_E_C_N_O_]) ON [PRIMARY]


GO

CREATE INDEX [SA19904] ON [dbo].[SA1990]([A1_FILIAL], [A1_TEL], [R_E_C_N_O_]) ON [PRIMARY]


GO
Programação SQL com SIGA Advanced / AP5

2.5.4. Problemas com conteúdo Nulo

Os Bancos de dados possuem o conteúdo nulo para todos os tipo de campos, mas
o nosso sistema não os utiliza, se por ventura qualquer tabela tenha algumas
linhas com alguma coluna com o valor nulo, isto pode provocar problemas que
aparentam ser erro de índice, como ex. Você tem a tabela de pedidos que com os
pedidos 000001,000002 e sua tabela por qualquer motivo não tem os contraints de
defaults na coluna filial, agora você faz a inserção do pedido 0000003 o sistema
irá apresentar um Browse ordenado por pedido da seguinte forma:

Considere a filial do arquivo de pedido de forma compartilhada.(Filiial=Branco)

Filial Pedido
--------- ------------
Null 000003
000001
000002

Neste exemplo você percebe que o pedido 000003 aparece em primeira ordem,
sendo o índice filial+pedido, ou seja, o valor nulo na tabela ASCII(Binary Order)
aparece antes do caracter espaço em branco.

Este problema muitas vezes causa a impressão que o índice esta com
problemas, por que a tela de Browse do Sigaadvanced / AP5 não apresenta a
coluna filial.

Alerta!: Tabelas com conteúdo nulo, geram vários problemas no sistema,


provavelmente deve gerar erros no TopConnect que o mesmo estará derrubando
as conexões quando elas fizerem acesso a este tipo de conteúdo (nulo). Existe um
utilitário que ajusta este problema se você o tiver, o mesmo esta disponível no site
da Microsiga, com o nome de DEFAULT.exe
Programação SQL com SIGA Advanced / AP5

2.6. Manutenção do Banco de dados


2.6.1. Aumentando a performance executando a operação de PACK

Esporadicamente você deve fazer uma manutenção no Banco de dados, quanto as


registros excluídos logicamente, os mesmo devem ser excluídos fisicamente, por que
a sua existência em grande quantidade e de forma seqüencial gera um grave
problema de performance no acesso aos dados.

Alerta!: Se você tiver este problema, utilize a operação de Pack do utilitário SDU
na tabela que possui registros excluídos , ou utilize o programa fonte PACK para
fazer esta operação em todas as tabelas.

Segue abaixo exemplo de fonte em RDMAKE, para fazer um pack em qualquer


Banco de dados.

Exemplo de fonte em ADVPL para executar um Pack no Banco de Dados , esta


rotina já prevê problema de estouro da área de LOG/RollBack de um Back de Dados
/*
Função ³PACK ³ Autor ³ Emerson/Vicente ³ Data ³ 16.12.99
Descrição ³Rotina RDMAKE para eliminar os registros deletados do banco
Uso ³RDMake <Programa.Ext> -w
Exemplo ³RDMake Pack.prw
*/
@ 96,42 TO 323,505 DIALOG oDlg5 TITLE "Rotina de Pack"
@ 8,10 TO 84,222
@ 91,168 BMPBUTTON TYPE 1 ACTION Execute(OkProc)
@ 91,196 BMPBUTTON TYPE 2 ACTION Close(oDlg5)
@ 23,14 SAY "Este programa ira fazer um pack em todos arquivos abertos pelo Advanced."
ACTIVATE DIALOG oDlg5
Return nil

Function OkProc
Close(oDlg5)
Processa( {|| Execute(RunProc) } )
Return
/*
Funcao ³RunProc
Descrição ³Executa o Processamento
*/
Function RunProc
DbSelectArea("SX2")
NrecnoSX2 := SX2->(Recno())
DbGoTop()
ProcRegua(reccount())
While !Eof()
If Select(SX2->X2_CHAVE) > 0
cQuery := 'SELECT MAX(R_E_C_N_O_) RECNO FROM ' + SX2->X2_ARQUIVO
dbUseArea(.T., "TOPCONN", TCGenQry(,,cQuery), 'CONT', .F., .T.)
nCont := 1
While nCont <= CONT->RECNO
cQuery := "DELETE FROM "+SX2->X2_ARQUIVO
cQuery := cQuery + " WHERE D_E_L_E_T_ = '*'"
cQuery := cQuery + " AND R_E_C_N_O_ between "+Str(nCont)+" AND
"+Str(nCont+1024)
nCont := nCont + 1024
TCSQLEXEC(cQuery)
Enddo
DbSelectArea("CONT")
DbCloseArea()
Endif
DbSelectArea("SX2")
dbSkip()
incproc()
Enddo
return
Programação SQL com SIGA Advanced / AP5

2.7. DBFNTX x TopConnect


2.7.1. Índices de produção

Todos os SGDB's utilizam o conceito de índices de produção portando uma aplicação


que utilize o TOPConnect não necessita ter todos os índices abertos para que os
mesmos sejam atualizados.

2.7.2. Funções em chaves de índices

Devido ao fato de os SGDB's não suportarem o uso de funções nos índices o


TOPConnect não tem como suportar este tipo de implementação.

As únicas funções suportadas são STR e DTOS.

Para a criação de índices que contenham campos caracter e numéricos na chave


apenas uma regra deve ser obedecida. A função STR deve obrigatoriamente receber
como parâmetros valores idênticos a definição da tabela.

Exemplo:
Em um arquivo com a seguinte estrutura:

CAMPO1 – Caracter de 10 posições.


CAMPO2 – Numérico de 14 Posições com 2 decimais.

Para se criar um índice que ordene o arquivo por CAMPO1 + CAMPO2 deverá o
seguinte comando ser utilizado:

INDEX ON CAMPO1+STR(CAMPO2,14,2) TO ARQIND

No caso do SigaAdvanced você deve colocar o índice na tabela SINDEX.

2.7.3. Índices condicionais

Nos gerenciadores de banco de dados não existe a figura dos índices condicionais.
Para se obter resultados semelhantes aos índices condicionais o TOPConnect
agregou nova funcionalidade ao filtro do SigaAdvanced / AP5.

Considere uma aplicação que crie o seguinte índice:

INDEX ON CODIGO,NOME FOR ESTADO = "SP" AND SALDO > 10000

Com o TOPConnect este índice seria o mesmo que:

SET FILTER TO ESTADO = "SP" .AND. SALDO > 10000 .AND.


ORDERBY(CODIGO,NOME)

dbSetOrder(0)

O TOPConnect permite o uso da função OrderBy nos filtros o que reproduz o mesmo
efeito de um índice filtrado.

O TOPConnect disponibiliza os dados na ordem solicitada pela cláusula OrderBy na


Ordem 0 do arquivo, não interferindo assim com os índices do arquivo.
Programação SQL com SIGA Advanced / AP5

2.7.4. Chaves numéricas compostas

Os SGDB's não suportam índices que contenham expressões ADVPL onde dois
campos numéricos são somados na chave.

Exemplo:
INDEX ON CPOVAL1 + CPOVAL2 TO ARQIND

2.7.5. Expressões de filtro com funções e variáveis

Uma vez que o TOPConnect utiliza a arquitetura Cliente/Servidor o servidor não tem
como avaliar o conteúdo de uma variável de memória ou o retorno de uma função do
cliente.

O TOPConnect permite a utilização de variáveis e funções nos filtros porém é


necessário ter em mente que a avaliação deste filtro ocorrerá no cliente e não no
servidor o que poderá resultar em problemas de performance.

Analisando o seguinte filtro :


SET FILTER TO CODIGO > "01000" .AND. CODIGO < "02000"

Este filtro contem apenas campos e constantes o que permite que sua avaliação seja
feita no servidor e que apenas os registros que obedeçam ao filtro venha para o
cliente.

Agora este:
SET FILTER TO CODIGO > RetornaCodigo()

Considerando que RetornaCodigo é uma função ADVPL da aplicação todas as linhas


deste arquivo serão avaliadas no cliente.

Visando minimizar os problemas de performance o TOPConnect conta com um


sistema chamado SFE (Smart Filter Engine) o que faz com que o máximo possível de
uma expressão seja avaliada no servidor.

Pôr exemplo:
SET FILTER TO ESTADO = 'SP' .AND. SALDO > 10000 .AND. CODIGO >
RetornaCodigo()
Nesta expressão somente virão para o cliente os registros onde os campos ESTADO
e SALDO obedeçam ao filtro e então o campo CODIGO será avaliado no cliente.
Programação SQL com SIGA Advanced / AP5

2.8. Comandos

Neste capítulo mencionaremos apenas os comandos da linguagem ADVPL que tem a sua
funcionalidade alterada ou complementada e os novos comandos implementados pelo
TOPConnect via RDD.

Para a utilização destes comandos o programa deverá conter a seguinte instrução:

#INCLUDE "TOPCONN.CH"

2.8.1. APPEND FROM

Em uma aplicação ADVPL o comando APPEND FROM é utilizado para se inserir


registros na Work Area corrente com registros vindos de outro arquivo DBF.
No TOPConnect o comando APPEND FROM importara registros de um arquivo
DBF para uma tabela do banco de dados.

No ADVPL opcionalmente poderá ser especificado o parâmetro VIA "TOPCONN" o


que fará com que registros de uma tabela sejam inseridos na Work Area corrente.

Exemplo
SELECT CLIENTES
//Importa registros de um DBF
APPEND FROM c:\temp\newcli.dbf
Ou
SELECT CLIENTES
//Importa registros da tabela NEWCLI
APPEND FROM NEWCLI VIA "TOPCONN"

2.8.2. COPY TO

Em uma aplicação ADVPL o comando COPY TO é utilizado para se copiar a


estrutura e os registros da Work Area corrente para um arquivo DBF.

No TOPConnect o comando COPY TO é utilizado para exportar a estrutura e os


registros de uma tabela do banco de dados para um arquivo DBF.

Assim como no comando APPEND FROM no ADVPL o parâmetro opcional VIA


também pode ser especificado.
Programação SQL com SIGA Advanced / AP5

2.8.3. USE

Abre uma tabela no banco de dados.


Sintaxe:

USE [<xcTable>

[INDEX <xcIndex list>]


[ALIAS <xcAlias>] [EXCLUSIVE | SHARED]
[NEW] [READONLY]
VIA "TOPCONN"

<cTable> O nome da tabela a ser aberta.


INDEX <cIndex List> Especifica o nome de 1 a 15 índices a serem abertos na
Work Area corrente.
ALIAS < cAlias> Especifica um nome para a Work Area onde a tabela será
aberta
EXCLUSIVE Especifica que apenas este usuário terá acesso a esta tabela.
Todas as outras tentativas de colocar esta mesma tabela em uso falharão.
SHARED Especifica que a tabela será aberta em modo compartilhado.
NEW Abre a tabela <cTable> na próxima Work Area disponível. Se esta clausula
não for especificada, <xcTable> será na Work Area corrente.
READONLY Abre <cTable> apenas para leitura.
VIA "TOPCONN" Este parâmetro indica ao ADVPL que esta Work Area será
gerenciada pelo TOPconnect.
Se nenhum parâmetro for especificado a tabela aberta na Work Area corrente será
fechada.

Exemplo
//Abre a tabela de Clientes em uma nova Work Area
USE clientes SHARED NEW VIA "TOPCONN"

2.8.4. BEGIN, COMMIT, ROLLBACK TRANSACTION

Marca o início de uma transação no banco de dados.


Desde o ponto em que uma aplicação executa um BEGIN TRANSACTION cada
APPEND ou REPLACE encontrado até um COMMIT TRANSACTION ou
ROLLBACK TRANSACTION serão considerados uma única transação.
Os demais usuários somente terão acesso aos novos registros ou às modificações
após um COMMIT TRANSACTION
Exemplo
#INCLUDE "TOPCONN.CH"
SELECT CLIENTES
if !Rlock()
Alert("Registro em uso!")
Return .f.
Endif
BEGIN TRANSACTION

//Atualiza saldo no cadastro de clientes

REPLACE SALDO WITH SALDO – nValor

//Adiciona um pedido
Programação SQL com SIGA Advanced / AP5

SELECT PEDIDOS
APPEND BLANK

REPLACE NUM WITH cNumero


REPLACE VALOR WITH nValor

SELECT ITEMS

APPEND BLANK

REPLACE NUM WITH cNumero


REPLACE QUANT WITH nQuant

.....

APPEND BLANK

REPLACE NUM WITH cNumero


REPLACE QUANT WITH nQuant

.....

COMMIT TRANSACTION
Programação SQL com SIGA Advanced / AP5

2.9. Funções
2.9.1. TCCANOPEN

Verifica a existência de tabelas e índices no servidor.


Sintaxe

TCCanOpen(cTable [, cIndice]) =>lógico

Exemplo
//Testa a existência da tabela customer
IF !TCCanOpen("CUSTOMER")
dbCreate("CUSTOMER", aStru, "TOPCONN")
ENDIF
USE CUSTOMER SHARED NEW VIA "TOPCONN"
//Testa a existência do índice
IF !TCCanOpen("CUSTOMER","CUSTCOD")
INDEX ON CODIGO TO CUSTCOD
ELSE
SET INDEX TO CUSTCOD
ENDIF
...

2.9.2. TCCONTYPE

Especifica o protocolo de comunicação a ser utilizado pelo TOPConnect.


Sintaxe

TCConType(<cType>)

Onde <cType> pode ser:

TCPIP Utiliza o protocolo TCP/IP.


NPIPE Utiliza o protocolo Named Pipes.
APPC Utiliza o protocolo APPC.
BRIDGE Utiliza o utilitário TOPBrigde para comunicação de estações DOS
NPIPE com servidor AS/400 utilizando TCP/IP.
Exemplo
#INCLUDE "TOPCONN.CH"
//Especifica conexão TCP/IP
TCConType("TCPIP")
//Conecta-se ao ambiente SIGAADV no Microsoft SQL-Server
TCLink("MSSQL/SIGAADV")

2.9.3. TCDELFILE

Exclui uma tabela no servidor.


Sintaxe

TCDelFile(<cTable>)

Onde <cTable> é o nome da tabela a ser excluída.


Exemplo
TCDelFile("CUSTOMER")
Programação SQL com SIGA Advanced / AP5

2.9.4. TCGETDB

Retorna o Tipo de Banco de Dados corrente

cDataBase := TCGETDB()

Onde os valores de retorno são :

MSSQL Microsoft SQL-Server 6.5


MSSQL7 Microsoft SQL-Server 7.0
ORACLE Oracle
DB2 IBM Universal Database
SYBASE Sybase SQL-Server
ANYWHERE Sybase SQL Anywhere
ANYSYBASE Sybase SQL Anywhere
(Emulando Sybase SQL-Server)
INFORMIX Informix

2.9.5. TCLINK

Abre uma conexão com o Servidor TOPConnect.


Sintaxe

nCon := TCLink(<cConectString>,<cServer>)

Onde o parâmetro <cConnectString> é composto por:

Para TOPConnect NT : Nome do Banco de Dados / Nome do Ambiente


Para TOPConnect/400: Nome do Ambiente

O parâmetro <cServer> contém:


Para conexões NamedPipe, APPC e Brigde : O nome do servidor TOPConnect
Para conexões TCP/IP : O endereço IP do servidor TOPConnect
Para o TOPConnect NT acessando Oracle, um ambiente é o nome do Alias criado
com o utilitário SQL-Net.

Para o TOPConnect NT acessando os demais SGDB's um ambiente é um System


DSN criado através do ODBC Data Source Administrator.

Para o TOPConnect AS/400 um ambiente é uma Library criada através do


comando CRTTOPENV do TOPConnect.

Para informações sobre a criação de ambientes consulte o manual de instalação


do TOPConnect.

Esta é a lista de Bancos de Dados hoje suportados e seus respectivos nomes


compor a string de conexão com o TOPConnect NT:

Microsoft SQL-Server 6.5 MSSQL


Microsoft SQL-Server 7.0 MSSQL7
Oracle ORACLE
IBM Universal Database DB2
Sybase SQL-Server SYBASE
Sybase SQL Anywhere ANYWHERE
Sybase SQL Anywhere
Programação SQL com SIGA Advanced / AP5

(Emulando Sybase SQL-Server) ANYSYBASE


Informix INFORMIX

A função TCLink retorna ou o número da conexão ou um valor negativo contendo o


código do erro.

Exemplo

//Conecta-se ao Microsoft SQL-Server no ambiente SIGAADV


//Protocolo Named Pipes
TCConType("NPIPE")

nCon := TCLink("MSSQL/SIGAADV","TOPSRV")
if nCon < 0 //Conexões com retorno < 0 significam erro
Alert("Falha de conexão com o TOPConnect")
endif
//Protocolo TCP/IP
TCConType("TCPIP")
//Conecta-se ao Oracle – no ambiente TESTES
nCon := TCLink("ORACLE/TESTES",172.16.1.2)

//Protocolo APPC
//Conecta-se ao AS/400 no ambiente PRODUCAO
nCon := TCLink("PRODUCAO","TOP400")
Programação SQL com SIGA Advanced / AP5

2.9.6. TCQUERY

Executa uma Query no servidor e coloca seu retorno em uma WorkArea.


Sintaxe:

TCQUERY [<cSQLExpr>

[ALIAS <xcAlias>]
[NEW]
VIA "TOPCONN"

<cSQLExpr> Expressão SQL a ser enviada ao servidor.


ALIAS < cAlias> Especifica um nome para a Work Area a ser aberta
NEW Abre a tabela <cTable> na próxima Work Area disponível. Se esta clausula
não for especificada, <xcTable> será na Work Area corrente.
VIA "TOPCONN" Este parâmetro indica ao ADVPL que esta Work Area será
gerenciada pelo TOPconnect.
A Work Area criada com o comando TCQUERY é READ-ONLY, portanto não é
permitido o uso de APPEND's ou REPLACE's.
O TOPConnect tem apenas um cursor para a Query executada portando apenas
os seguintes comandos são suportados em uma Work Area criada com TCQUERY:
GO TOP - DbGoTop()
GO BOTTOM - DbGoBottom()
SKIP - DbSkip()
Eof()
Bof()

Obs: Ao executar uma Query que retorne um ou mais valores calculados, o nome
dos campos da WorkArea serão COLUMN1, COLUMN2... COLUMNn.
Exemplo

//Abre a tabela de Clientes em uma nova Work Area


cQuery := "SELECT a.codigo, b.nome FROM CLIENTES a, CLIDATA b ; WHERE
a.CODIGO = b.CODIGO ORDER BY CODIGO,NOME"
TCQUERY cQuery ALIAS CLIENTES NEW VIA "TOPCONN"
dbGoTop()
While !Eof()
? CODIGO,NOME
dbSkip()
end
USE
cQuery := 'SELECT SUM(VALOR),SUM(SALDO) FROM CUSTOMER'
TCQUERY cQuery NEW VIA "TOPCONN"
?COLUMN1 //Somatoria dos valores
?COLUMN2 //Somatoria dos saldos
Programação SQL com SIGA Advanced / AP5

2.9.7. TCQUIT

Encerra todas as conexões com o TOPConnect


Sintaxe
TCQuit()

2.9.8. TCSETCONN

Seleciona conexão ativa.

Sintaxe
TCSETCONN(<nConn>)
Onde <nConn> é o número da conexão.
Exemplo
// Abre conexão com o ambiente de Produção
nCon1 := TCLink("MSSQL/PRODUCAO")
if nCon1 < 0
Alert("Falha conectando ambiente de Produção")
QUIT
endif

// Abre conexão com o ambiente de Testes


nCon2 := TCLink("MSSQL/TESTES")

if nCon2 < 0 then


Alert("falha conectando ambiente de Testes")
QUIT
endif

TCSetConn(nCon1)

//Abre tabela de Clientes no ambiente de produção


USE CUSTOMER ALIAS PROD SHARED NEW VIA "TOPCONN"

TCSetConn(nCon2)

//Abre tabela de Clientes no ambiente de testes


USE CUSTOMER ALIAS TEST SHARED NEW VIA "TOPCONN"
...

2.9.9. TCSETFIELD

Esta função serve como apoio ao comando TCQUERY, na recuperação de campos


tipo NUMERIC, DATE e LOGICAL, pois os mesmos são gravados fisicamente no
Banco de Dados como caracteres, e no caso dos numéricos como float.

Sintaxe
TCSetField(<cAlias>, <cField> ,<cType>, [<Prec.Inteira>,<Prec.Decimal>] )

Onde <cAlias> é o alias da WorkArea, <cField> é o nome do campo e <cType> é o


tipo desejado para o campo.

Exemplo
Programação SQL com SIGA Advanced / AP5

TCQUERY "SELECT NOME, DATA, MARRIED, VALOR FROM CUSTOMER"


ALIAS QUERY VIA "TOPCONN"

TCSetField("QUERY","DATA","D")
TCSetField("QUERY","VALOR","N",12,2)

Dentro de um programa ADVPL já podemos considerar como um campo data não


mais um campo caracter como é o seu armazenamento.

O campo Data só é retornado como um campo caracter por que estamos


utilizando a função TCQUERY, se não o tratamento é automático.

2.9.10. TCSPEXEC

Executa uma Stored Procedure no Banco de Dados.

Devido a uma limitação em alguns dos Bancos de Dados suportados na obtenção


dos tipos de parâmetros (se são de INPUT e/ou OUTPUT) todos as Stored
Procedures a serem executadas através do TOPConnect deverão obedecer o
seguinte padrão de nomenclatura de seus parâmetros :

Parâmetros de INPUT devem começar com IN_... Ex. IN_VALOR.


Parâmetros de OUTPUT devem começar com OUT_... Ex. OUT_CODIGO

Após a execução de uma Stored Procedure o TOPConnect retornará ao ADVPL um


array com 'n' elementos, onde n é o número de parâmetros de OUTPUT da Stored
Procedure.

Sintaxe
<aRet> := TCSPExec(<cSPName>,[<xParam1>,<xParam2>...<xParamN>])

Onde <aRet> é um array com os parâmetros de retorno da Stored Procedure e


<cSPName> é o nome da Stored Procedure a ser executada e os demais
parâmetros variam conforme a definição da Stored Procedure.

Exemplo
//Verifica se a Stored Procedure Teste existe no Servidor
If TCSPExist("TESTE")
//Executa a Stored Procedure Teste
aRet := TCSPExec("TESTE","JOSE",1000)
if aRet <> nil

For i:= 1 to Len(aRet)


//Mostra os valores de retorno
?aRet[i]
Next
Else
?"Erro executando Stored Procedure"
?"Mensagem: "+TCSQLError()
Endif
EndIf
Programação SQL com SIGA Advanced / AP5

2.9.11. TCSPEXIST

Verifica a existência de uma determinada Stored Procedure no servidor.


Sintaxe
<lExist> := TCSPExist(<cSPName>)

Onde <lExist> indica se a Stored Procedure existe ou não e <cSPName> é o nome


da Stored Procedure procurada.

Exemplo
If SPExist("CALCCUSTO")
TCSPExec("CALCCUSTO")
Endif

2.9.12. TCSQLERROR

Retorna o último erro registrado pelo TOPConnect durante a execução de uma


Query.

Sintaxe
<cError> := TCSQLError()

Onde <cError> é a mensagem de erro.


Exemplo
If TCSQLExec("UPDATE CUSTOMER SET VALUE=0") < 0 then
?TCSQLError()
Endif

OBS: Esta é a mesma mensagem que esta registrada no log de eventos do


TopConnect Manager.

2.9.13. TCSQLEXEC

Executa comandos SQL no servidor.


Sintaxe

<nRet> := TCSQLExec(<cCommand>)

Onde <nRet> retorna um valor negativo em caso de erros e <cCommand> e o


comando SQL a ser executado.
Exemplo
TCSQLExec("UPDATE CUSTOMER SET VALUE=0)
Programação SQL com SIGA Advanced / AP5

2.9.14. TCSRVTYPE

Retorna o Tipo do Servidor onde esta sendo executado o TOPConnect.


Sintaxe

<cType> := TCSrvType()

Onde <cType> é o tipo do servidor podendo Ter seu conteúdo igual a "WinNT" ou
"AS/400".
Exemplo
TCLink("MSSQL/TESTE","TOPSRV")
?TCSrvtype()

2.9.15. TCUNLINK

Encerra uma conexão com o TOPConnect.


Sintaxe

TCUnlink(<nConn>)

Onde <nConn> é o número da conexão retornado pela função TCLink()


Exemplo
TCConType("NPIPE")
nConn := TCLink("MSSQL/TOPCONN","TOPSRV")
TCUnLink(nConn)

2.9.16. TCCHKOBJ*

Verifica a existência de um objeto no servidor AS/400


Sintaxe

<nError> := TCChkObj(<cObj>,<cLibrary>,<cType>)

Onde:
<nError> é 0 quando o objeto existe ou o número do erro no AS/400.
<cLibrary> é o nome da biblioteca que deve conter o objeto.
<cType> é o tipo de objeto AS/400. Ex: *FILE, *PGM, etc.
Exemplo
nError := TCChkObj("CALCCUST","PRODUCAO","*PGM")
ESTA FUNÇÃO SE APLICA APENAS PARA O TOPCONNECT AS/400

( * )Funções apenas para o TOPConnect rodando em servidores AS/400.


Programação SQL com SIGA Advanced / AP5

2.9.17. TCEXEERROR*

Retorna uma string com a mensagem de erro retornada pela execução das
funções TCPGMEXE() e TCSYSEXE().
Sintaxe
<cError> := TCExeError()

Onde <cError> é a string com a mensagem de erro.


Exemplo
?TCExeError()

( * )Funções apenas para o TOPConnect rodando em servidores AS/400.

2.9.18. TCPGMEXE*

Executa um programa no servidor AS/400

TCPGMEXE( program name )

( * )Funções apenas para o TOPConnect rodando em servidores AS/400.

2.9.19. TCSYSEXE*

cCommand := "CRTCBLMOD MODULE("+cTDataBase+"/"+


cName+"F"+cCrrEmp+") "
cCommand += "SRCFILE("+cTDataBase+"/QSPSRC) "
cCommand += "SRCMBR("+cName+"F"+cCrrEmp+") "
cCommand += "REPLACE(*YES)"

TCSysExe( cCommand )

( * )Funções apenas para o TOPConnect rodando em servidores AS/400.


Programação SQL com SIGA Advanced / AP5

2.10. Performance
2.10.1. Otimizando seu código

A linguagem ADVPL tem um enfoque posicional, recuperando os dados utilizando


orientação a registros, enquanto aos Bancos de Dados SQL recuperam os dados
por blocos de dados.
Devido a esta diferença conceitual, vários pontos devem ser levados em
consideração para que se possa obter uma boa performance e utilizar os recursos
de uma aplicação Client/Server.

2.10.2. Leitura Sequencial

Operações de leitura seqüencial de uma tabela podem levar a problemas de


performance.
Vamos analisar o seguinte código:
dbSelectArea("CLIENTES")
nValor := 0
Do While !Eof()
If ESTADO = "SP"
nValor += SALDO
Endif
DbSkip()
End

O código acima fará com que todas as linhas(registros) da tabela venham para o
Client, o que irá gerar um número de Queries no servidor igual ao número de linhas
da tabela e cada uma delas irá recuperar apenas uma linha, subtilizando a
capacidade de processamento do servidor.

O código acima poderia ser substituído por:


TCQUERY "SELECT SUM(SALDO) ;
FROM CLIENTES ;
WHERE ESTADO = 'SP'" NEW
nValor := COLUMN1
Com a utilização do comando TCQUERY todo a somatória é feita no servidor
retornando assim para a aplicação apenas uma linha com o resultado desejado.
Programação SQL com SIGA Advanced / AP5

2.10.3. O uso de filtros

O uso de filtros em aplicações ADVPL são conhecidos como fonte de problemas de


performance. Isto se deve ao fato de que todos os registros são avaliados pela
estação.

O mesmo não ocorre utilizando o TOPConnect, pois o filtro é avaliado pelo próprio
servidor vindo para a estação apenas os registros que respeitem a condição do
filtro.

Para que um filtro tenha uma boa performance é necessário que a expressão do
filtro corresponda a um índice no servidor, caso contrário, para poder avaliar o filtro
o servidor SQL terá que ler linha a linha da tabela.

2.10.4. Stored Procedures

O uso de Stored Procedures é a maneira mais eficiente de uma aplicação se


utilizar dos benefícios da arquitetura Cliente/Servidor.

O TOPConnect suporta o uso de Stored Procedures conforme documentado na


função TCSPExec()
Programação SQL com SIGA Advanced / AP5

2.11. Integração com outros aplicativos


2.11.1. Incluindo registros nas tabelas do SigaAdvanced / AP5

As tabelas criadas no Banco de dados pode receber inserções de outros


aplicativos, esta inserção deve ser feita contemplando as seguintes operações :

 Antes de inserir o registro você deve obter o número máximo da coluna


R_E_C_N_O_ existente na tabela
 Deste número você deve somar 1
 Logo em seguida fazer a inserção propriamente dita do registro
 Se o registro não for inserido com sucesso você deve voltar ao primeiro passo.

Alerta!: Em alguns Bancos de Dados o Topconnect estará registrando no log de


eventos do Topconnect Manager, um mensagem de alerta dizendo que existe
duplicidade de registro. (Desconsiderar esta mensagem, de tempos em tempos
você deve limpar o Log do TopConnect.

2.11.2. Excluindo registros ( Sempre Marcar )

Quando houver necessidade de exclusão de registro por outros aplicativos você


deve apenas fazer uma operação de alteração do registro, colocando o símbolo de
‘*’ na coluna D_E_L_E_T_, principalmente se esta operação for concorrente com
o SigaAdvanced / AP5.

2.11.3. Vantagens e Desvantagens

As vantagens deste processo é a agilidade na integração entre os sistemas, não


existe a necessidade de gerar arquivos textos, para depois fazermos a
integração. Principalmente em situações on-line , utilizar o recurso do Banco é
uma das melhores saídas.

As desvantagens deste processo, são que você deve estar ciente de todas
atualizações que são feitas na base de dados no sistema, já que o sistema esta
desta forma vulnerável a problemas inesperados.

Normalmente aconselhamos a sempre fazer a atualização em tabelas específicas


e depois criar rotinas pelo sistema o qual repassarão os dados destas tabelas
para as tabelas definitivas, desta forma vamos evitar problemas na atualização de
versão, ou até em alguma mudança de estrutura que o configurador faça.(Você
estará perdendo os triggers desta tabela).
Programação SQL com SIGA Advanced / AP5

3. Ferramenta importante
3.1. Instalador de Stored Procedures no Banco de Dados

Alguns clientes utilizam rotinas como Stored Procedures para agilizar alguns processos
críticos do sistema, para instalação destas Storeds Procedures você devem possuir o
arquivo com o nome de SIGAXXX.SPS, onde o XXX é o tipo de Banco de Dados que o
Cliente estará utilizando ex: SIGASQ7 (MSSQL 7.0), SIGAIFX (INFORMIX), SIGAORA
(ORACLE)

Após a confirmação desta operação todas as Procedures que estiverem disponíveis neste
arquivo serão compiladas para a empresa em questão, se o cliente tiver mais do que uma
empresa e ele deseja instalar as procedures em todas as empresas ele precisa entrar
em cada empresa.

Se houver qualquer problema na instalação das Stores Procedures


será gerado um arquivo de log chamado SPBuild.LOG no diretório
\SIGAADV\. E também será apresentado o erro no Log do TopConnect.
Programação SQL com SIGA Advanced / AP5

Programação SQL (Avançado)

Com SigaAdvanced/ AP5

Banco de Dados Oracle é a marca registrada da Oracle Corporation.


Banco de Dados MSSQL Server é a marca registrada da Microsoft.
Banco de Dados Informix é a marca registrada da Informix Corporation.
Banco de Dados Sybase é a marca registrada da Sybase Corporation.
Banco de Dados UDB é a marca registrada da IBM.

Este material é de efeito didático/suporte e não pode ser reproduzido sem autorização da
MicroSiga.
Programação SQL com SIGA Advanced / AP5

CopyRight © 2000 Microsiga Software S.A.

Índice
4. Structure Query Language (SQL)
4.1. Introdução
4.2. SELECT
4.3. Clausula WHERE
4.4. INSERT
4.5. UPDATE
4.6. DELETE
4.7. Funções de Agregação
4.7.1. SUM
4.7.2. COUNT
4.7.3. AVG
4.7.4. MAX
4.7.5. MIN
4.7.6. Group By
4.7.7. Clausula HAVING
4.7.8. Clausula DISTINCT
4.8. Função de String ( SUBSTRING/SUBSTR )
4.9. ORDER BY
4.10. JOINS
4.10.1. INNER JOIN
4.10.2. LEFT JOIN ou LEFT OUTER JOIN
4.10.3. RIGHT JOIN ou RIGHT OUTER JOIN
4.10.4. FULL JOIN ou FULL OUTER JOIN
4.10.5. CROSS JOIN
4.11. UNIONS
4.12. SUB SELECTS
4.13. TRIGGERS
4.14. STORED PROCEDURES
4.15. CURSORES

5. Programando SQL em RDMAKES


5.1. Query’s
5.2. Função ChangeQuery
5.3. Stored Procedures
5.4. Comandos DDL
5.4.1. Truncate Table
5.4.2. Drop Table
Programação SQL com SIGA Advanced / AP5
Programação SQL com SIGA Advanced / AP5

6. Structure Query Language (SQL)


6.1. Introdução

Neste capítulo iremos estudar as sintaxes básicas da linguagem SQL, mostraremos


exemplos e executando exercícios práticos.

Você vai perceber que a linguagem SQL é sempre em comandos textos que são
enviados ao servidor, este fará a compilação e execução da query. Este processo é feito a
cada requisição ao servidor. Você perceberá que quanto menos solicitações melhor a
performance obtida.

Existem vários comandos de manipulação do banco de dados como criação de tabela,


índices, constraints, defaults, etc. Neste curso não estaremos comentando estes
comandos, pois os mesmos dependem exclusivamente da plataforma e são de
responsabilidade e conhecimento de um DBA. Indiretamente estas operações são
executadas pelo TopConnect em comandos TC’s. Querendo utilizar uma destas funções,
consulte o manual do banco de dados ou procure a orientação de um DBA.

Ferramentas de trabalho para os Banco de Dados mais comuns MSSQL Server (isql/w ,
Query Analyzer), Oracle (WorkSheet) e Informix (SQL Editor) . Estas ferramentas são
muito similares a editores de texto, ou seja, você deve digitar todo o comando, e o mesmo
será submetido imediatamente ao SGDB.

A seguir estaremos apresentando a sintaxe da linguagem SQL.


Programação SQL com SIGA Advanced / AP5

6.2. SELECT

Este comando recupera informações gravadas no banco de dados. A diferença básica de


um select para um programa orientado a registros é que em um select você pode
recuperar várias linhas para uma determinada condição, ao contrário do programa que
teria que efetuar vários acessos para obter o mesmo resultado.
Ex. se você escrever um programa padrão ADVPL você terá que posicionar o registro,
fazer um laço até o final do arquivo, lendo o próximo registro, etc. Veja agora como fazer
em linguagem SQL.

Sintaxe:

SELECT [<apelido>.] <Nome da Coluna> [<Nome de Retorno>], n...


FROM <Nome da Tabela> [<apelido>], n ...

<Nome da Coluna> => Informar o nome(s) da(s) coluna(s) da(s) tabela(s) que você
deseja apresentar/manipular em seu aplicativo. Se você informar o símbolo ‘*’ (Asterisco)
o comando assumirá todas as colunas da tabela.

<Nome da Tabela> => Informar o nome de todas as tabelas associadas ao resultado


esperado. Se existirem colunas com mesmo nome em tabelas diferentes, você deverá
associar o nome da tabela junto ao nome da coluna (SA1010.A1_NOME).

<Apelido> => sinônimo utilizado para referenciar uma tabela correspondente.

<Nome de Retorno> => Será o nome da coluna apresentado para sua aplicação como o
nome original de resultado da query.

 Ex. Select simples

SELECT *
FROM SA1990

SELECT A1_COD, A1_NOME


FROM SA1990

Quando utilizamos ‘*’ o SGDB estará retornando todas as colunas da tabela,


recomendamos sempre informar as colunas que realmente você estará utilizando,
por que, se a tabela possuir muitas colunas o tempo de resposta do seu select
pode ser mais demorado.

 Ex. Select com colunas compostas [ +, -, *, /, (, ) ]

SELECT C6_QTDVEN * C6_PRCVEN VALOR


FROM SC6990

Para colunas do tipo numérico podemos fazer qualquer tipo de cálculo, lembrando
que para o cálculo seräo considerados os operadores que estiverem dentro de
parênteses para depois consideram os externos e assim por diante.
Vale a pena lembrar que no banco de dados os campos numéricos säo do tipo
float, portanto näo possuem limitaçäo de casas decimais. No momento de utilizar o
resultado devemos efetuar o arredondamento dos dados com a funçäo abaixo:

Sintaxe: ROUND(Coluna,Precisão)
Programação SQL com SIGA Advanced / AP5

SELECT round(round(C6_QTDVEN,4)*round(C6_PRCVEN,2),2)VALOR
FROM SC6990

 Ex. Select com uso de apelido nas colunas

SELECT A1_COD CODIGO, A1_NOME NOME, R_E_C_N_O_ RECNO


FROM SA1990

Neste caso percebemos que na frente de cada nome de coluna existe um outro
nome referenciando a respectiva tabela que chamamos de apelido. Este nome será
utilizado como referência na resposta da query.

 Ex. Select com uso de apelido nas tabelas

SELECT SA1.A1_COD, SA1.A1_NOME


FROM SA1990 SA1

SELECT SA1.A1_COD CODIGO, SA1.A1_NOME NOME, SC5.C5_NUM NUM


FROM SA1990 SA1, SC5990 SC5

Agora temos um exemplo de utilização de mais de uma tabela, para referenciarmos


a vários campos

 Ex. Select com uso de múltiplas tabelas com seleção de todas as colunas
de uma tabela, e apenas algumas de outra tabela

SELECT SA1.*, SC5.C5_NUM NUM


FROM SA1990 SA1, SC5990 SC5

 Ex. Select com concatenação de colunas

SELECT A1_COD + A1_LOJA CODIGO


FROM SA1990

Obs: Para Banco de dados Oracle e Informix utilize dois pipes ‘|’ no lugar de ‘+’.

6.3. Clausula WHERE

Esta clausula é uma das mais importantes do comando SELECT, pois é a partir dela que
filtramos os dados da query. O filtro que estaremos informando é muito parecido com a
que utilizamos em uma função indregua(), em ADVPL.

Sintaxe:

SELECT [<apelido>.] <Nome da Coluna> [<Nome de Retorno>], n...


FROM <Nome da Tabela> [<apelido>], n ...
WHERE <Condição de filtro>

<Condição de filtro> - informar uma expressão lógica que estará eliminando as linhas que
estiverem dentro do contexto informado.
Dentro da condição de filtro você pode utilizar os seguintes operadores :
Programação SQL com SIGA Advanced / AP5

= (igualdade)
> (maior que)
< (menor que)
>= (maior que ou igual a)
<= (menor que ou igual a)
<> (diferente)
!= (diferente) (não é SQL-92 padrão).
!< (Não menor a) (não é SQL-92 padrão).
!> (Não maior a) (não é SQL-92 padrão).
AND Verdadeiro se ambas expressões forem verdadeiras
OR Verdadeiro se qualquer expressão for verdadeira
BETWEEN Verdadeiro se a expressão esta dentro de um
determinado intervalo
EXISTS Verdadeiro se uma subquery contém alguma linha
IN Verdadeiro se o operando é igual a uma das
expressões da lista
NOT Inverte o valor de qualquer outra expressão boleana
LIKE ([ _ ],%) Verdadeiro se a expressão fixa for encontrada.

 Ex. Select utilizando alguns dos operadores

SELECT *
FROM SE1990
WHERE E1_FILIAL = '01'
AND E1_CLIENTE BETWEEN ' ' AND 'zzzzzz'
AND E1_LOJA BETWEEN ' ' AND 'zz'
AND E1_PREFIXO LIKE 'P%'
AND E1_NUM BETWEEN ' ' AND 'zzzzzz'
AND E1_VENCREA BETWEEN '20000225' AND '20001231'
AND E1_EMISSAO <= '20001231'
AND E1_TIPO IN ('DP ','NF ','AB-','NCC','NCD')
AND NOT E1_EMISSAO = '20000401'
AND D_E_L_E_T_ <> '*'

Nota: A clausula where deve sempre compor o máximo possível


de campos que se adequam a uma chave de índice e o máximo
de filtro possível definido, desta forma as suas query’s terão
sempre um resposta rápida.
Programação SQL com SIGA Advanced / AP5

6.4. INSERT

Este comando insere uma linha em uma tabela ou visão. A inserção feita pelo
SigaAdvanced/AP5 se utiliza deste comando. Em um programa ADVPL não é necessário a
utilização deste comando, pois o TopConnect efetua uma série de controles na operação.

Sintaxe:

INSERT INTO <Nome da Tabela> | <Nome da Visão>


[ ( Coluna 1,Coluna n,... )
VALUES ]
( Conteúdo_coluna1, Conteúdo_coluna n,...)

 Ex. Insert completo

INSERT INTO SA4990


(A4_FILIAL,A4_COD,A4_NOME,A4_NREDUZ,A4_VIA,A4_EST,
A4_CGC,A4_TEL,R_E_C_N_O_)
VALUES (' ','000001','TRANSP.AREO', 'STAR', 'AEREA',
'SP', '51706778000151','765-7865',1)

 Ex. Insert informando só o conteúdo a inserir

INSERT INTO SA4990


(' ','000001','TRANSP.AREO', 'STAR', 'AEREA',
'SP', '51706778000151','765-7865',1)

 Ex. Insert com select e numeração automática da coluna R_E_C_N_O_

INSERT INTO SA4990


SELECT ' ','000001','TRANSP.AREO','STAR',
'AEREA','SP', '51706778000151','765-7865',
isNull(max(R_E_C_N_O_),0) + 1
FROM SA4990

Obs: função isnull é do MSSQL Server, para Oracle utilize nvl

Nota: Recomendamos sempre informar o nome das colunas que estarão sendo inseridas,
pois se optar pela omissão dos nomes, os valores deverão ser informados na ordem de
criação da tabela.
Programação SQL com SIGA Advanced / AP5

6.5. UPDATE

Comando para fazer alterações nas informações gravadas. Estas alterações podem ser
processadas linha a linha ou em bloco, de acordo com a condição de filtro informada.

Sintaxe:

UPDATE [FROM] <Nome da Tabela>


SET <Nome da Coluna> = <expressão> | <valor>
WHERE <Condicional de Filtro>

Lembre-se que o comando update faz controle transacional implícito, ou seja, enquanto o
comando não for executado até o seu final com sucesso o dado não estará confirmado
(Commit). Para a execução do comando o banco utilizará área de log, portanto se formos
executar um update cujo filtro atinja toda a tabela, será necessário espaço suficiente para
alocar a transação na área de log.

 Ex. Update padrão utilizado pelo SigaAdvanced / AP5


UPDATE SA4990
SET A4_NOME = ‘TRANSPORTADORA STAR LTDA’
WHERE R_E_C_N_O_ = 10

Neste exemplo será alterado apenas as linhas que tenham Recno igual a 10,
como o recno é chave única da tabela apenas um registro será alterado.

 Ex. Update com condicional diferente


UPDATE SA4990
SET A4_NOME = 'TRANSPORTADORA STAR LTDA'
WHERE A4_COD = '000001'
AND D_E_L_E_T_ <> '*'

Neste caso a alteração será feita em todas as linhas que possuem a coluna
A4_COD = '000001' e a coluna D_E_L_E_T_ diferente de '*'.

 Ex. Update com campos de cálculo


UPDATE SB1990
SET B1_PRV1 = B1_PRV1 + ( (B1_PRV1 + 10) / 100 )
WHERE D_E_L_E_T_ <> '*'

Neste exemplo o registro será alterado com o resultado do cálculo.

 Ex. Update padrão de exclusão de registro do SigaAdvanced / AP5


UPDATE SA4990
SET D_E_L_E_T_ = ‘*’
WHERE R_E_C_N_O_ = 10

Neste exemplo o registro é excluído para o sistema SigaAdvanced, ou seja,


através da programação em ADVPL o comando delet() estará executando o
update acima, fazendo uma marca no registro, pois a exclusão é lógica.

Alerta: Nunca execute um comando update sem um condicional, desta forma você estará
alterando todos as linhas da tabela e também estará correndo o risco de estourar a área
de log do Banco de Dados. (Utilize ferramentas como SDU ou Configurador)
Programação SQL com SIGA Advanced / AP5

6.6. DELETE

Comando para efetuar a exclusão física da informação. No SigaAdvanced / AP5 apenas o


comando pack executa esta instrução. A construção deste comando é semelhante ao
update, possuindo também opção de filtro.

Sintaxe:

DELETE [FROM] <Nome da Tabela>


WHERE <Condicional de Filtro>

Lembre-se que o comando delete faz controle transacional implícito, ou seja, enquanto o
comando não for executado até o seu final com sucesso o dado não estará confirmado
(Commit). Para a execução do comando o banco utilizará área de log, portanto se formos
executar um delete cujo filtro atinja toda a tabela, será necessário espaço suficiente para
alocar a transação na área de log.

 Ex. Delete para exclusão física de uma linha

DELETE SA4990
WHERE R_E_C_N_O_ = 10

Neste exemplo será excluído apenas as linhas que tenham Recno igual a 10,
como o recno é chave única da tabela apenas um registro será alterado.

 Ex. Delete com condicional diferente

DELETE SA4990
WHERE A4_COD = '000001'
AND D_E_L_E_T_ = '*'

Neste caso a exclusão será feita em todas as linhas que possuem a coluna
A4_COD = '000001' e a coluna D_E_L_E_T_ igual a '*'.

Note: Em alguns Bancos de Dados você pode utilizar o comando TRUNCATE TABLE,
que estará fazendo o mesmo que um comando ZAP em ADVPL. Só que esta operação é
extremamente rápida, para conhecedores de Cobol, esta operaçào é conhecida como
OPEN OUTPUT. Atenção depois desta operação não existe mais como recuperar as
linhas da tabela. (Esta operação não utiliza LOG).

Alerta: Nunca execute um comando delete sem um condicional, desta forma você estará
excluindo todos as linhas da tabela e também estará correndo o risco de estourar a área
de log do Banco de Dados.
Programação SQL com SIGA Advanced / AP5

6.7. Funções de Agregação

O objetivo principal das funções de agregação é criar colunas de acumuladores de um


determinado agrupamento definido pela cláusula group by. Se esta cláusula não for
informada o retorno será sempre uma linha.

Sintaxe genérica para as funções:

SELECT [DISTINCT] [<FUNCAO>( ] <Nome da coluna|*>[)]


[ WHERE <Condicional de Filtro por linha> ]
[ GROUP BY <Colunas de agrupamento, coluna1, …, coluna16> ]
[ HAVING <Condição de agrupamento> ]

6.7.1. SUM

Esta função retorna a somatória de uma coluna(s) defina pelo usuário.

 Ex. Select que retorna o total de saldo de duplicatas de clientes

SELECT SUM(A1_SALDUP)
FROM SA1990
WHERE D_E_L_E_T_ <> ‘*’

Este exemplo retorna o saldo total dos títulos em aberto eliminando os registros
excluídos da base de dados.

6.7.2. COUNT

Esta função totaliza o número de linhas na tabela, utlizando filtro para tal. Se for
informado o nome de uma coluna, a função contará apenas as linhas que não
estiverem com seu conteúdo nulo..

 Ex. Select que retorna o total de linhas da tabela

SELECT COUNT(*)
FROM SA1990
WHERE D_E_L_E_T_ <> ‘*’

Este exemplo retorna o total de linhas não excluídas.

 Ex. Select que retorna o total de linhas da tabela, considerando somente


uma coluna

SELECT COUNT(A1_FILIAL)
FROM SA1990
WHERE D_E_L_E_T_ <> ‘*’

Este exemplo retorna o total de linhas não excluídas. Se houver conteúdo nulo
em alguma linha, esta não será contada.
Programação SQL com SIGA Advanced / AP5

6.7.3. AVG

Esta função retorna a média aritmética da coluna informada, filtrando as linhas pela
clausula where ou having.

 Ex. Select para média do saldo a receber de cada cliente

SELECT AVG(A1_SALDUP)
FROM SA1990
WHERE D_E_L_E_T_ <> ‘*’

Este exemplo retorna a média da coluna A1_SALDUP, não considerando as


linhas excluídas.

6.7.4. MAX

Esta função retorna o valor máximo da coluna especificada.

 Ex. Select para o maior valor da coluna R_E_C_N_O_

SELECT MAX(R_E_C_N_O_)
FROM SA1990

Este exemplo retornará o maior valor da coluna, o mesmo é muito usado para
se saber qual a próxima seqüência disponível. Nunca despreze as linhas
excluídas, por que este número é sequencial e único na tabela.

6.7.5. MIN

Esta função retorna o valor mínimo da coluna especificada.

 Ex. Select do menor valor da data de emissão do pedido

SELECT MIN(C6_EMISSAO)
FROM SC6990
WHERE C6_CLI = ‘ 123456’
AND D_E_L_E_T_ <> ‘*’

Este exemplo retorna o menor valor da coluna C6_EMISSAO.

6.7.6. GROUP BY

Esta cláusula define quais colunas determinam o agrupamento do comando select.

 Ex. Select para obter valor total de pedidos por cliente e data

SELECT C6_CLI, C6_LOJA, C6_EMISSAO, SUM(C6_VALOR) TOTAL


FROM SC6990
WHERE D_E_L_E_T_ <> ‘*’
GROUP BY C6_CLI, C6_LOJA, C6_EMISSAO

Este exemplo faz a somatória da coluna C6_VALOR, efetuando o agrupamento


do resultado por cliente, loja e data.
Programação SQL com SIGA Advanced / AP5

 Ex. Select para obter quantidade de pedidos por cliente

SELECT C6_CLI, C6_LOJA, COUNT(*) QTD_PED


FROM SC6990
WHERE D_E_L_E_T_ <> ‘*’
AND C6_EMISSAO between ‘19990101’ and ‘19990630’
GROUP BY C6_CLI, C6_LOJA

Este exemplo retorna a quantidade de pedidos, agrupando o resultado por


cliente e loja, filtrando o resultado por data de emissão.

6.7.7. HAVING

Esta cláusula tem por finalidade filtrar os dados que estão numa condição de
agrupamento. Apesar de ser uma cláusula de filtro (semelhante à cláusula where),
ela é dependente da cláusula group by.

 Ex. Select para obter códigos inseridos com duplicidade

SELECT A1_COD, A1_LOJA, COUNT(*)


FROM SA1990
WHERE D_E_L_E_T_ <> ‘*’
GROUP BY A1_COD, A1_LOJA
HAVING COUNT(*) > 1

Este exemplo faz a contagem do número de ocorrências de código e loja em


duplicidade. A clausula having elimina as ocorrências não duplicadas, ou seja
count(*) <= 1.

6.7.8. DISTINCT

Esta cláusula elimina repetições para a coluna informada.

 Ex. Select para obter todos os CFOs utilizados pelo cliente

SELECT DISTINCT F4_CF


FROM SF4990
WHERE D_E_L_E_T_ <> ‘*’

Este exemplo elimina do resultado os CFO’s repetidos.

 Ex. Select para obter código das filiais com linhas existentes (válido para
tabela com X2_MODO = ‘E’)

SELECT DISTINCT A1_FILIAL


FROM SA1990
WHERE D_E_L_E_T_ <> ‘*’
Programação SQL com SIGA Advanced / AP5

6.8. Função de String ( SUBSTRING/SUBSTR )

Esta função é idêntica a função SUBSTR usada em ADVPL, e pode ser utilizada em
qualquer ponto do select onde informamos uma coluna.

OBS: Para MSSQL Server e Sybase a sintaxe é SUBSTRING. Em Oracle e Informix a


sintaxe é SUBSTR.

Sintaxe genérica para as funções:

SUBSTR[ING](<Origem>,<n posição inicial>,<tamanho em bytes>)

 Ex. Select para apresentar parte do nome do cliente para todos os


clientes que possuem ‘5’ na segunda posição do código.

SELECT SUBSTRING(A1_NOME,1,20) NOME


FROM SA1990
WHERE SUBSTRING(A1_CODIGO,2,1) = ‘5’
AND D_E_L_E_T_ <> ‘*’

Não recomendamos a utilização da função na cláusula WHERE, pois o banco terá


que fazer uma busca em toda a tabela, por não possuir índice do conteúdo a ser
filtrado.

6.9. ORDER BY

Esta cláusula ordena o resultado do select independente do índice utilizado para acessar
o dado. O resultado pode ser ordenado de forma crescente(ASC) ou decrescente (DESC).
Um detalhe importante para performance do comando é tentar utilizar na cláusua ORDER
BY as mesmas colunas que compõe um índice já existente no banco de dados, caso
contrário o banco terá que ordernar os dados na área temporária (TempDB) o que pode
prejudicar a performance do comando.

Sintaxe :

SELECT …
FROM …
ORDER BY <Coluna1> [ASC|DESC],…,<Coluna16> [ASC|DESC]

 Ex. Select para apresentar o nome de todos os clientes por ordem


decrescente de nome.

SELECT A1_NOME
FROM SA1990
WHERE D_E_L_E_T_ <> ‘*’
ORDER BY A1_NOME DESC

 Ex. Select para apresentar os cliente por ordem de código e loja de forma
crescente.

SELECT A1_COD, A1_LOJA


FROM SA1990
WHERE D_E_L_E_T_ <> ‘*’
ORDER BY A1_COD, A1_LOJA
Programação SQL com SIGA Advanced / AP5

Note que neste exemplo não é necessário informar a expressão ASC, para
obter o resultado de forma crescente.

Nota : Em alguns casos de query´s você irá perceber que o resultado já estará
apresentando as linhas por uma certa ordenação, isto que dizer que o banco
de dados utilizou um índice para resolver o problema, mas isto não indica que
sempre o dado será retornado nesta ordem, portanto se você precisar que o
dados retornados estejam ordenados você dever sempre informa o ORDER
BY.

6.10. JOINS

Esta operação é uma das mais poderosas expressões de um comando select, pois com
ela podemos relacionar tabelas obtendo informações cruzadas. Este comando pode ser
escrito de duas formas, porém alguns bancos suportam apenas uma delas. Estaremos
apresentado esta forma e comentaremos suas diferenças.

O relacionamento entre as tabelas é feito utilizando o símbolo de igualdade entre duas


colunas, sendo uma coluna de cada tabela. Lembre-se que o relacionamento é feito de
forma binária, ou seja, só podemos relacionar duas tabelas de cada vez, mas podemos
com isto relacionar quantas tabelas desejarmos, limitado pela capacidade do banco de
dados.

Como recomendação devemos sempre tentar relacionar no máximo quatro tabelas, lógico
que existe exceções, mas sempre que houver o relacionamento de muitas tabelas o
banco de dados precisará de mais tempo para conseguir resolver o problema e em alguns
caso não será viável. Existem várias situações que dependem de experiência e teste para
conseguirmos chegar na melhor solução possível.

Sempre que utilizarmos joins devemos sempre informar todas as tabelas que serão
relacionadas na clausula from e todos os seus relacionamentos na clausula where se por
acaso não for feito o relacionamento de uma destas tabelas o banco de dados estará
fazendo um produto cartesiano (CROSS JOIN) entre todas as linhas da tabela que não foi
relacionado com as demais tabelas.Se isto acontecer o servidor poderá ter sérios
problemas de uso excessivo de CPU.

Existem Cinco tipos de JOINS :

6.10.1.1. INNER JOIN

Um join simples é formado pelo relacionamento de duas ou mais tabelas.

 Ex. Select para retornar todas os pedidos de venda e o nome do cliente

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5, SA1990 SA1
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'
Programação SQL com SIGA Advanced / AP5

 Ex. Select para retornar todas os pedidos de venda, nome do cliente e o


nome do Vendedor

SELECT SC5.C5_NUM, SA1.A1_NOME, SA3.A3_NOME


FROM SC5990 SC5, SA1990 SA1, SA3990 SA3
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SA3.A3_FILIAL = ‘01’
AND SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SA1.A1_VEND = SA3.A3_COD <= Define o rel.SA1->SA3
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

6.10.1.2. LEFT JOIN ou LEFT OUTER JOIN

O resultado de um left join inclui todas as linhas da tabela que foi específica a
esquerda da clausula LEFT OUTER , ou seja, independente de existir ou não um
dado relacionado na tabela informada mais a direita da tabela todas as linhas
referentes a tabela da esquerda serão retornadas. Nas linhas que não existe um
linha de relação com a tabela a direita os campos desta tabela serão retornados
com valor nulo.

O símbolo ( *= ) representa um LEFT JOIN para o MSSQL Server, Sybase, o


campo indicado do lado do símbolo (*) será o da tabela que você deseja que todas
as linhas sejam retornadas independente da existência do dado da coluna mais a
direita, vamos ver exemplos de query’s para estes Bancos de Dados.

 Ex. Select para retornar todas os pedidos de venda e o nome do cliente


mesmo que não exista o cliente

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5, SA1990 SA1
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SC5.C5_CLIENTE *= SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI *= SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

 Ex. Select para retornar todas os pedidos de venda, nome do cliente e o


nome do Vendedor mesmo que não exista o Vendedor

SELECT SC5.C5_NUM, SA1.A1_NOME, SA3.A3_NOME


FROM SC5990 SC5, SA1990 SA1, SA3990 SA3
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SA3.A3_FILIAL = ‘01’
AND SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SA1.A1_VEND *= SA3.A3_COD <= Define o rel.SA1->SA3
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'
Programação SQL com SIGA Advanced / AP5

O símbolo (+ ) representa um LEFT JOIN para o Oracle, o campo indicado do lado


do campo que será o da tabela que você deseja que todas as linhas sejam
retornadas independente da existência do dado da coluna mais a direita, vamos
ver exemplos de query’s para estes Bancos de Dados.

 Ex. Select para retornar todas os pedidos de venda e o nome do cliente


mesmo que não exista o cliente

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5, SA1990 SA1
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND (+) SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1
AND (+) SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

 Ex. Select para retornar todas os pedidos de venda, nome do cliente e o


nome do Vendedor mesmo que não exista o Vendedor

SELECT SC5.C5_NUM, SA1.A1_NOME, SA3.A3_NOME


FROM SC5990 SC5, SA1990 SA1, SA3990 SA3
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SA3.A3_FILIAL = ‘01’
AND SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
AND (+) SA1.A1_VEND = SA3.A3_COD <= Define o rel.SA1->SA3
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

Na clausula from especificamos a palavra OUTER que irá representar um LEFT


JOIN para o Informix, o campo da esquerda será o da tabela que você deseja que
todas as linhas sejam retornadas independente da existência do dado da coluna
mais a direita, vamos ver exemplos de query’s para estes Bancos de Dados.

 Ex. Select para retornar todas os pedidos de venda e o nome do cliente


mesmo que não exista o cliente

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5 OUTER, SA1990 SA1
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

 Ex. Select para retornar todas os pedidos de venda, nome do cliente e o


nome do Vendedor mesmo que não exista o Vendedor

SELECT SC5.C5_NUM, SA1.A1_NOME, SA3.A3_NOME


FROM SC5990 SC5, SA1990 SA1 OUTER, SA3990 SA3
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SA3.A3_FILIAL = ‘01’
Programação SQL com SIGA Advanced / AP5

AND SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1


AND SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SA1.A1_VEND = SA3.A3_COD <= Define o rel.SA1->SA3
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

Nota: Não é possível fazer outer joins subsequentes, ou seja, se você fizer
outer join de uma tabela que logo em seguida tem um relacionamento com
outra tabela.

6.10.1.3. RIGHT JOIN or RIGHT OUTER JOIN

O resultado de um Right join inclui todas as linhas da tabela que foi específica a
direita da clausula RIGHT OUTER , ou seja, independente de existir ou não um
dado relacionado na tabela informada mais a esquerda da tabela todas as linhas
referentes a tabela da direita serão retornadas. Nas linhas que não existe um
linha de relação com a tabela a direita os campos desta tabela serão retornados
com valor nulo.

O símbolo ( =* ) representa um RIGHT JOIN para o MSSQL Server, Sybase, o


campo indicado do lado do símbolo (*) será o da tabela que você deseja que todas
as linhas sejam retornadas independente da existência do dado da coluna mais a
esquerda, vamos ver exemplos de query’s para estes Bancos de Dados.

 Ex. Select para retornar todos os clientes mesmo que não exista pedidos
relacionados

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5, SA1990 SA1
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SC5.C5_CLIENTE =* SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI =* SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

O símbolo ( + ) representa um RIGHT JOIN para o Oracle, o campo indicado do


lado do símbolo (+) será o da tabela que você deseja que todas as linhas sejam
retornadas independente da existência do dado da coluna mais a esquerda,
vamos ver exemplos de query’s para estes Bancos de Dados.

 Ex. Select para retornar todos os clientes mesmo que não exista pedidos
relacionados

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5, SA1990 SA1
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SC5.C5_CLIENTE = SA1.A1_COD (+) <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI = SA1.A1_LOJA (+) <= Define o rel.SC5->SA1
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'
Programação SQL com SIGA Advanced / AP5

Na clausula from especificamos a palavra OUTER que irá representar um RIGHT


JOIN para o Informix, o campo indicado do lado direito que você deseja que todas
as linhas sejam retornadas independente da existência do dado da coluna mais a
esquerda, vamos ver exemplos de query’s para estes Bancos de Dados.

 Ex. Select para retornar todos os clientes mesmo que não exista pedidos
relacionados

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5, SA1990 SA1 OUTER
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

Nota: Não é possível fazer outer joins subsequentes, ou seja, se você fizer outer
join de uma tabela que logo em seguida tem um relacionamento com outra tabela.

6.10.1.4. FULL JOIN or FULL OUTER JOIN

Um full outer join é o resultado de um inner join + right join + left join , desta forma
você terá o resultado com todas as linhas da primeira tabela mais o resultado com
todas as linhas da Segunda tabela e apresentará em mesma linha os itens que
forem possíveis de relacionamento.

Exemplo para o Banco MSSQL Server e Sybase

 Ex. Select para retornar todos os clientes e todos os pedidos mesmo que
não exista pedidos ou clientes relacionados

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5 FULL OUTER SA1990 SA1
ON SC5.C5_CLIENTE = SA1.A1_COD <= Define o rel.SC5->SA1
AND SC5.C5_LOJACLI = SA1.A1_LOJA <= Define o rel.SC5->SA1
WHERE SC5.C5_FILIAL = '01'
AND SA1.A1_FILIAL = ' '
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

Nota: Nos demais Bancos de Dados não existem este tipo de join. Mas existem
outras formar de resolver este problema utilizando inner join + left join + right join +
unions , iremos ver a seguir como utilizar o union desta forma teremos a solução
também para os demais bancos de dados, e até mesmo os que tem a opção.

6.10.1.5. CROSS JOIN

É o mais simples e dificilmente utilizado, ele simplesmente faz um produto


cartesiano em as tabelas especificadas na clausula where. O comando é o mesmo
em todos os Bancos de Dados.

 Ex. Select para retornar todos os clientes e todos os pedidos mesmo que
não exista pedidos ou clientes relacionados
Programação SQL com SIGA Advanced / AP5

SELECT SC5.C5_NUM, SA1.A1_NOME


FROM SC5990 SC5, SA1990 SA1

Nota: Existem vários casos de programadores que esquecem de relacionar


algumas tabelas, e acontece um grande problema de performance. Se você
esquecer de relacionar uma tabela e a mesma tiver um número de linhas muito
grande nós estaremos consumindo processador e i/o de disco inutilmente.

6.11. UNIONS
A expressão UNION permite você combinar o resultado de dois ou mais SELECTs
em um único resultado. Uma das restrições para combinar o uso de UNION é que
devemos ter uma estrutura única em cada um dos SELECTs, ou seja, os mesmos
devem ter o mesmo número de colunas devem ter tipos de dados compatíveis.

 Ex. Select para retornar todos os clientes da empresa 01 e da empresa 02


desconsiderando duplicidades

SELECT A1_COD, A1_LOJA, A1_NOME


FROM SA1990
UNION
SELECT A1_COD, A1_LOJA, A1_NOME
FROM SA1010

 Ex. Select para retornar todos os clientes da empresa 01 e da empresa 02


considerando todas duplicidades

SELECT A1_COD, A1_LOJA, A1_NOME


FROM SA1990
UNION ALL
SELECT A1_COD, A1_LOJA, A1_NOME
FROM SA1010

Nota: Existem vários casos de programadores que esquecem de informar a


clausula ALL , e acontece um grande problema que parece estar faltando registros
de dados nos programas.
Programação SQL com SIGA Advanced / AP5

6.12. SUB SELECTS

Sub-Selects é utilizado na clausula where onde pode ser utilizado para fazer relação de
verificação de um determinado dado da tabela original com várias linhas de uma outra
tabela sem obrigatoriamente ser parte integrante de um join.

 Ex. Select para retornar todos os clientes que compraram o produto ‘x’,
utilizando operador IN

SELECT DISTINCT SA1.A1_NOME


FROM SA1990 SA1, SC5990 SC5
WHERE SA1.A1_FILIAL = ' '
AND SC5.C5_FILIAL = '01'
AND SC5.C5_CLIENTE = SA1.A1_COD
AND SC5.C5_LOJACLI = SA1.A1_LOJA
AND SC5.C5_NUM IN ( SELECT C6_NUM
FROM SC6990 SC6
WHERE SC6.FILIAL = ‘ ’
AND SC6.C6_NUM = SC5.C5_NUM
AND SC6.C6_PRODUTO = ‘X’
AND SC6.D_E_L_E_T_ <> ‘*’ )
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

 Ex. Select para retornar todos os clientes que compraram o produto ‘x’,
utiliando operador EXISTS

SELECT DISTINCT SA1.A1_NOME


FROM SA1990 SA1, SC5990 SC5
WHERE SA1.A1_FILIAL = ' '
AND SC5.C5_FILIAL = '01'
AND SC5.C5_CLIENTE = SA1.A1_COD
AND SC5.C5_LOJACLI = SA1.A1_LOJA
AND EXISTS ( SELECT *
FROM SC6990 SC6
WHERE SC6.FILIAL = ‘ ’
AND SC6.C6_NUM = SC5.C5_NUM
AND SC6.C6_PRODUTO = ‘X’
AND SC6.D_E_L_E_T_ <> ‘*’ )
AND SC5.D_E_L_E_T_ <> '*'
AND SA1.D_E_L_E_T_ <> '*'

6.13. TRIGGERS

Triggers são gatilhos do Banco de Dados, os quais são acionados por uma inclusão,
alteração ou exclusão de uma linha em uma determinada tabela. Cada Banco de Dados
trata as triggers de uma forma, hoje o SigaAdvanced/AP5 não utiliza estas triggers. As
triggers podem ser utilizadas pelos clientes, considerando o seguinte problema: Se
houver qualquer alteração na estrutura de uma tabela o sistema irá reconstruir a tabela
mas com sua nova estrutura, índices, defaults, ..., mas não irá recriar os triggers
criados associados a estas tabelas.
Programação SQL com SIGA Advanced / AP5

6.14. STORED PROCEDURES

Stored Procedures são programas feitos em linguagem nativa do Banco de Dados em


questão que não utiliza o padrão ANSI/92, uma Stored Procedure pode resolver vários
problemas de performance, por que uma procedure além de estar sendo executada no
próprio Banco de dados que elimina o tráfego de rede, ela já foi pré-compilada, ou seja,
ela não passa por uma re-compilação a cada vez que ela é executada.

A Microsiga utiliza várias Storeds Procedures em processos críticos para clientes com
Base de Dados muito grande, em clientes pequenos este processo não se faz
necessário, além de que clientes menores utilizam servidores menores que nem sempre
tem capacidade suficiente para executar SP’s.

Como cada Banco de Dados possui Stored Procedures diferentes a Microsiga criou o seu
compilador que chamamos SQLParser e adotamos um dialeto único e um único fonte o
qual é convertido para cada tipo de Banco de Dados, evitando desta forma divergência
entre programas fontes.

6.15. CURSORES

Cursores são definições de conjunto de dados que serão manipulados linha a linha, ou
seja, da mesma forma que estamos acostumados a fazer uma linguagem posicional onde
os registros são tratados um a um.

7. Programando SQL em RDMAKES


7.1. Query’s

Agora vamos ver um exemplo prático utilizando query diretamente no Banco de Dados

Programa interno do SigaAdvanced/AP5


As linhas em negrito são as modificações para utilizar linguagem SQL

//³Funcao ³ FA130Imp
//³Descricao ³ Imprime relatorio dos Titulos a Receber
//³Sintaxe e ³ FA130Imp(lEnd,WnRel,cString)
Static Function FA130Imp(lEnd,WnRel,cString)
Local CbCont
Local CbTxt
Local limite := 220
Local nOrdem
Local lContinua := .T.
Local cCond1,cCond2,cCarAnt
Local nTit0:=0
Local nTit1:=0
Local nTit2:=0
Local nTit3:=0
Local nTit4:=0
Local nTit5:=0
Local nTotJ:=0
Local nTot0:=0
Local nTot1:=0
Local nTot2:=0
Local nTot3:=0
Local nTot4:=0
Local nTotTit:=0
Local nTotJur:=0
Local nTotFil0:=0
Local nTotFil1:=0
Programação SQL com SIGA Advanced / AP5

Local nTotFil2:=0
Local nTotFil3:=0
Local nTotFil4:=0
Local nTotFilTit:=0
Local nTotFilJ:=0
Local aCampos:={}
Local aTam:={}
Local nAtraso:=0
Local nTotAbat:=0
Local nSaldo:=0
Local dDataReaj
Local dDataAnt := dDataBase
Local lQuebra
Local nMesTit0 := 0
Local nMesTit1 := 0
Local nMesTit2 := 0
Local nMesTit3 := 0
Local nMesTit4 := 0
Local nMesTTit := 0
Local nMesTitj := 0
Local cIndexSe1
Local cChaveSe1
Local nIndexSE1
Local dDtContab
Local cTipos := ""
Local aStru := SE1->(dbStruct()), ni
Local nTotsRec := SE1->(RecCount())

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Ponto de entrada para Filtrar os tipos sem entrar na tela do ³
//³ FINRTIPOS(), localizacao Argentina. ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄJose Lucas, Localiza‡”es ArgentinaÄÙ
IF EXISTBLOCK("F130FILT")
cTipos := EXECBLOCK("F130FILT",.f.,.f.)
ENDIF

nOrdem:=aReturn[8]
cMoeda:=Str(mv_par15,1)

PRIVATE dBaixa := dDataBase


PRIVATE cFilDe,cFilAte

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Vari veis utilizadas para Impress„o do Cabe‡alho e Rodap‚ ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
cbtxt := "* indica titulo provisorio, P Indica Saldo Parcial"
cbcont := 1
li := 80
m_pag := 1

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ POR MAIS ESTRANHO QUE PARE€A, ESTA FUNCAO DEVE SER CHAMADA AQUI! ³
//³ ³
//³ A fun‡„o SomaAbat reabre o SE1 com outro nome pela ChkFile para ³
//³ efeito de performance. Se o alias auxiliar para a SumAbat() n„o ³
//³ estiver aberto antes da IndRegua, ocorre Erro de & na ChkFile, ³
//³ pois o Filtro do SE1 uptrapassa 255 Caracteres. ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
SomaAbat("","","","R")

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Atribui valores as variaveis ref a filiais ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
If mv_par21 == 2
cFilDe := cFilAnt
cFilAte:= cFilAnt
ELSE
cFilDe := mv_par22 // Todas as filiais
cFilAte:= mv_par23
Programação SQL com SIGA Advanced / AP5

Endif

dbSelectArea("SM0")
dbSeek(cEmpAnt+cFilDe,.T.)

While !Eof() .and. M0_CODIGO == cEmpAnt .and. M0_CODFIL <= cFilAte

dbSelectArea("SE1")
cFilAnt := SM0->M0_CODFIL
Set Softseek On

If mv_par19 == 1
titulo := titulo + OemToAnsi(STR0026) //" - Analitico"
Else
titulo := titulo + OemToAnsi(STR0027) //" - Sintetico"
cabec1 := OemToAnsi(STR0044) //" |
Titulos Vencidos | Titulos a Vencer | Vlr.juros ou (Vencidos+Vencer)"
cabec2 := OemToAnsi(STR0045) //" | Valor
Nominal Valor Corrigido | Valor Nominal | permanencia "
EndIf

#IFDEF TOP
if TcSrvType() != "AS/400"
cQuery := "SELECT * "
cQuery += " FROM "+ RetSqlName("SE1")
cQuery += " WHERE E1_FILIAL Between '" + cFilDe + "' AND '"+ cFilAte + "'"
cQuery += " AND D_E_L_E_T_ <> '*' "
endif
#ENDIF

IF nOrdem = 1
cChaveSe1 :=
"E1_FILIAL+E1_NOMCLI+E1_CLIENTE+E1_LOJA+E1_PREFIXO+E1_NUM+E1_PARCELA+E1_TIPO"
#IFDEF TOP
if TcSrvType() == "AS/400"
cIndexSe1 := CriaTrab(nil,.f.)
IndRegua("SE1",cIndexSe1,cChaveSe1,,Fr130IndR(),"Selecionando Registros...")
nIndexSE1 := RetIndex("SE1")
dbSetOrder(nIndexSe1+1)
dbSeek(xFilial("SE1"))
else
cOrder := SqlOrder(cChaveSe1)
endif
#ELSE
cIndexSe1 := CriaTrab(nil,.f.)
IndRegua("SE1",cIndexSe1,cChaveSe1,,Fr130IndR(),"Selecionando Registros...")
nIndexSE1 := RetIndex("SE1")
dbSetIndex(cIndexSe1+OrdBagExt())
dbSetOrder(nIndexSe1+1)
dbSeek(xFilial("SE1"))
#ENDIF
cCond1 := "E1_CLIENTE <= mv_par02"
cCond2 := "E1_CLIENTE + E1_LOJA"
titulo := titulo + OemToAnsi(STR0017) //" - Por Cliente"

Elseif nOrdem = 2
SE1->(dbSetOrder(1))
#IFNDEF TOP
dbSeek(cFilial+mv_par03+mv_par05)
#ELSE
if TcSrvType() == "AS/400"
dbSeek(cFilial+mv_par03+mv_par05)
else
cOrder := SqlOrder(IndexKey())
endif
#ENDIF
cCond1 := "E1_NUM <= mv_par06"
cCond2 := "E1_NUM"
titulo := titulo + OemToAnsi(STR0018) //" - Por Numero"
Elseif nOrdem = 3
Programação SQL com SIGA Advanced / AP5

SE1->(dbSetOrder(4))
#IFNDEF TOP
dbSeek(cFilial+mv_par07)
#ELSE
if TcSrvType() == "AS/400"
dbSeek(cFilial+mv_par07)
else
cOrder := SqlOrder(IndexKey())
endif
#ENDIF
cCond1 := "E1_PORTADO <= mv_par08"
cCond2 := "E1_PORTADO"
titulo := titulo + OemToAnsi(STR0019) //" - Por Banco"
Elseif nOrdem = 4
SE1->(dbSetOrder(7))
#IFNDEF TOP
dbSeek(cFilial+DTOS(mv_par09))
#ELSE
if TcSrvType() == "AS/400"
dbSeek(cFilial+DTOS(mv_par09))
else
cOrder := SqlOrder(IndexKey())
endif
#ENDIF
cCond1 := "E1_VENCREA <= mv_par10"
cCond2 := "E1_VENCREA"
titulo := titulo + OemToAnsi(STR0020) //" - Por Data de Vencimento"
Elseif nOrdem = 5
SE1->(dbSetOrder(3))
#IFNDEF TOP
dbSeek(cFilial+mv_par11)
#ELSE
if TcSrvType() == "AS/400"
dbSeek(cFilial+mv_par11)
else
cOrder := SqlOrder(IndexKey())
endif
#ENDIF
cCond1 := "E1_NATUREZ <= mv_par12"
cCond2 := "E1_NATUREZ"
titulo := titulo + OemToAnsi(STR0021) //" - Por Natureza"
Elseif nOrdem = 6
SE1->(dbSetOrder(6))
#IFNDEF TOP
dbSeek( cFilial+DTOS(mv_par13))
#ELSE
if TcSrvType() == "AS/400"
dbSeek( cFilial+DTOS(mv_par13))
else
cOrder := SqlOrder(IndexKey())
endif
#ENDIF
cCond1 := "E1_EMISSAO <= mv_par14"
cCond2 := "E1_EMISSAO"
titulo := titulo + OemToAnsi(STR0042) //" - Por Emissao"
Elseif nOrdem == 7
cChaveSe1 := "E1_FILIAL+DTOS(E1_VENCREA)
+E1_PORTADO+E1_PREFIXO+E1_NUM+E1_PARCELA+E1_TIPO"
#IFNDEF TOP
cIndexSe1 := CriaTrab(nil,.f.)
IndRegua("SE1",cIndexSe1,cChaveSe1,,Fr130Ind7(),"Selecionando Registros...")
nIndexSE1 := RetIndex("SE1")
dbSetIndex(cIndexSe1+OrdBagExt())
dbSetOrder(nIndexSe1+1)
dbSeek(xFilial("SE1"))
#ELSE
if TcSrvType() == "AS/400"
cIndexSe1 := CriaTrab(nil,.f.)
IndRegua("SE1",cIndexSe1,cChaveSe1,,Fr130Ind7(),"Selecionando Registros...")
nIndexSE1 := RetIndex("SE1")
Programação SQL com SIGA Advanced / AP5

dbSetOrder(nIndexSe1+1)
dbSeek(xFilial("SE1"))
else
cOrder := SqlOrder(cChaveSe1)
endif
#ENDIF
cCond1 := "E1_VENCREA <= mv_par10"
cCond2 := "DtoS(E1_VENCREA)+E1_PORTADO"
titulo := titulo + OemToAnsi(STR0023) //" - Por Vencto/Banco"
Elseif nOrdem = 8
SE1->(dbSetOrder(2))
#IFNDEF TOP
dbSeek(cFilial+mv_par01,.T.)
#ELSE
if TcSrvType() == "AS/400"
dbSeek(cFilial+mv_par01,.T.)
else
cOrder := SqlOrder(IndexKey())
endif
#ENDIF
cCond1 := "E1_CLIENTE <= mv_par02"
cCond2 := "E1_CLIENTE"
titulo := titulo + OemToAnsi(STR0024) //" - Por Cod.Cliente"
Elseif nOrdem = 9
cChave :=
"E1_FILIAL+E1_PORTADO+E1_SITUACA+E1_NOMCLI+E1_PREFIXO+E1_NUM+E1_PARCELA+E1_TIPO"
#IFNDEF TOP
dbSelectArea("SE1")
cIndex := CriaTrab(nil,.f.)
IndRegua("SE1",cIndex,cChave,,fr130cheq(),"Selecionando Registros...")
nIndex := RetIndex("SE1")
dbSetIndex(cIndex+OrdBagExt())
dbSetOrder(nIndex+1)
dbSeek(xFilial("SE1"))
#ELSE
if TcSrvType() == "AS/400"
dbSelectArea("SE1")
cIndex := CriaTrab(nil,.f.)
IndRegua("SE1",cIndex,cChave,,fr130cheq(),"Selecionando Registros...")
nIndex := RetIndex("SE1")
dbSetOrder(nIndex+1)
dbSeek(xFilial("SE1"))
else
cOrder := SqlOrder(cChave)
endif
#ENDIF
cCond1 := "E1_PORTADO <= mv_par08"
cCond2 := "E1_PORTADO+E1_SITUACA"
titulo := titulo + OemToAnsi(STR0025) //" - Por Banco e Situacao"
Endif

If mv_par19 == 1
titulo := titulo + OemToAnsi(STR0026) //" - Analitico"
Else
titulo := titulo + OemToAnsi(STR0027) //" - Sintetico"
cabec1 := OemToAnsi(STR0044) //"Nome do Cliente |
Titulos Vencidos | Titulos a Vencer | Vlr.juros ou (Vencidos+Vencer)"
cabec2 := OemToAnsi(STR0045) //" | Valor
Nominal Valor Corrigido | Valor Nominal | permanencia "
EndIf

cFilterUser:=aReturn[7]
Set Softseek Off

#IFDEF TOP
if TcSrvType() != "AS/400"
cQuery += " AND E1_CLIENTE between '" + mv_par01 + "' AND '" + mv_par02 + "'"
cQuery += " AND E1_PREFIXO between '" + mv_par03 + "' AND '" + mv_par04 + "'"
cQuery += " AND E1_NUM between '" + mv_par05 + "' AND '" + mv_par06 + "'"
cQuery += " AND E1_PORTADO between '" + mv_par07 + "' AND '" + mv_par08 + "'"
Programação SQL com SIGA Advanced / AP5

cQuery += " AND E1_VENCREA between '" + DTOS(mv_par09) + "' AND '" + DTOS(mv_par10) + "'"
cQuery += " AND E1_NATUREZ between '" + mv_par11 + "' AND '" + mv_par12 + "'"
cQuery += " AND E1_EMISSAO between '" + DTOS(mv_par13) + "' AND '" + DTOS(mv_par14) + "'"
cQuery += " AND E1_LOJA between '" + mv_par24 + "' AND '" + mv_par25 + "'"
cQuery += " AND E1_EMISSAO <= '" + DTOS(dDataBase) + "'"

If mv_par20 == 2
cQuery += ' AND E1_SALDO <> 0'
Endif
cQuery += " ORDER BY "+ cOrder

cQuery := ChangeQuery(cQuery)

dbSelectArea("SE1")
dbCloseArea()
dbSelectArea("SA1")

dbUseArea(.T., "TOPCONN", TCGenQry(,,cQuery), 'SE1', .F., .T.) //= O mesmo que TCQUERY

For ni := 1 to Len(aStru)
If aStru[ni,2] != 'C'
TCSetField('SE1', aStru[ni,1], aStru[ni,2],aStru[ni,3],aStru[ni,4])
Endif
Next
endif
#ENDIF
SetRegua(nTotsRec)

While &cCond1 .and. !Eof() .and. lContinua .and. E1_FILIAL == xFilial("SE1")

#IFNDEF WINDOWS
Inkey()
If LastKey() = K_ALT_A
lEnd := .t.
Endif
#ENDIF

IF lEnd
@PROW()+1,001 PSAY OemToAnsi(STR0028) //"CANCELADO PELO OPERADOR"
Exit
Endif

IncRegua()

Store 0 To nTit1,nTit2,nTit3,nTit4,nTit5

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Carrega data do registro para permitir ³
//³ posterior analise de quebra por mes. ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
dDataAnt := Iif(nOrdem == 6 , SE1->E1_EMISSAO, SE1->E1_VENCREA)

cCarAnt := &cCond2

While &cCond2==cCarAnt .and. !Eof() .and. lContinua .and. E1_FILIAL == xFilial("SE1")

#IFNDEF WINDOWS
Inkey()
If LastKey() = K_ALT_A
lEnd := .t.
Endif
#ENDIF

IF lEnd
@PROW()+1,001 PSAY OemToAnsi(STR0028) //"CANCELADO PELO OPERADOR"
lContinua := .F.
Exit
EndIF

IncRegua()
Programação SQL com SIGA Advanced / AP5

dbSelectArea("SE1")
//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Filtrar com base no Pto de entrada do Usuario... ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄJose Lucas, Localiza‡”es ArgentinaÄÙ
If !Empty(cTipos)
If !(SE1->E1_TIPO $ cTipos)
dbSkip()
Loop
End
Endif

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Considera filtro do usuario ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
If !Empty(cFilterUser).and.!(&cFilterUser)
dbSkip()
Loop
Endif

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Nao ‚ retroativo, nem considera o titulo zerado ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
If mv_par20 == 2 .and. E1_SALDO = 0
dbSkip()
Loop
Endif

IF !Empty(E1_FATURA) .and. Substr(E1_FATURA,1,6) != "NOTFAT" .and. SE1->E1_DTFATUR <=


dDataBase
dbSkip()
Loop
Endif

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Verifica se trata-se de abatimento ou somente titulos³
//³ at‚ a data base. ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
IF SubStr(SE1->E1_TIPO,3,1)=="-".Or. SE1->E1_EMISSAO>dDataBase .or.;
(!Empty(E1_FATURA).and.Substr(E1_FATURA,1,6)=="NOTFAT".and.SE1->E1_EMISSAO >
dDataBase)
dbSkip()
Loop
Endif

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Verifica se ser impresso titulos provis¢rios ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
IF E1_TIPO == "PR " .and. mv_par16 == 2
dbSkip()
Loop
Endif

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Verifica se ser impresso titulos de Adiantamento ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
IF SE1->E1_TIPO $ "RA /"+MV_CRNEG .and. mv_par26 == 2
dbSkip()
Loop
Endif

// dDtContab para casos em que o campo E1_EMIS1 esteja vazio


dDtContab := Iif(Empty(SE1->E1_EMIS1),SE1->E1_EMISSAO,SE1->E1_EMIS1)

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Verifica se esta dentro dos parametros ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
dbSelectArea("SE1")
IF SE1->E1_CLIENTE < mv_par01 .OR. SE1->E1_CLIENTE > mv_par02 .OR. ;
SE1->E1_PREFIXO < mv_par03 .OR. SE1->E1_PREFIXO > mv_par04 .OR. ;
Programação SQL com SIGA Advanced / AP5

SE1->E1_NUM < mv_par05 .OR. SE1->E1_NUM >


mv_par06 .OR. ;
SE1->E1_PORTADO < mv_par07 .OR. SE1->E1_PORTADO > mv_par08 .OR. ;
SE1->E1_VENCREA < mv_par09 .OR. SE1->E1_VENCREA > mv_par10 .OR. ;
SE1->E1_NATUREZ < mv_par11 .OR. SE1->E1_NATUREZ > mv_par12 .OR. ;
SE1->E1_EMISSAO < mv_par13 .OR. SE1->E1_EMISSAO > mv_par14 .OR. ;
SE1->E1_LOJA < mv_par24 .OR. SE1->E1_LOJA > mv_par25 .OR. ;
dDtContab < mv_par27 .OR. dDtContab > mv_par28 .OR. ;
SE1->E1_EMISSAO > dDataBase
dbSkip()
Loop
Endif

If mv_par18 == 2 .and. E1_SITUACA $ "27"


dbSkip()
Loop
Endif

dDataReaj := IIF(SE1->E1_VENCREA < dDataBase ,;


IIF(mv_par17=1,dDataBase,E1_VENCREA),;
dDataBase)

If mv_par20 == 1 // Considera Data Base


nSaldo :=SaldoTit(SE1->E1_PREFIXO,SE1->E1_NUM,SE1->E1_PARCELA,SE1-
>E1_TIPO,SE1->E1_NATUREZ,"R",SE1->E1_CLIENTE,mv_par15,dDataReaj,,SE1->E1_LOJA)
Else
nSaldo := xMoeda(SE1->E1_SALDO,SE1->E1_MOEDA,mv_par15,dDataReaj)
Endif

If ! (SE1->E1_TIPO $ "RA /"+MV_CRNEG) .And. ;


!( MV_PAR20 == 2 .And. nSaldo == 0 ) // nao deve olhar abatimento pois e zerado o saldo na
liquidacao final do titulo
nSaldo-=SomaAbat(SE1->E1_PREFIXO,SE1->E1_NUM,SE1-
>E1_PARCELA,"R",mv_par15,dDataReaj,SE1->E1_CLIENTE,SE1->E1_LOJA)
EndIf
nSaldo:=Round(NoRound(nSaldo,3),2)

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Desconsidera caso saldo seja menor ou igual a zero ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
If nSaldo <= 0
dbSkip()
Loop
Endif

dbSelectArea("SA1")
MSSeek(cFilial+SE1->E1_CLIENTE+SE1->E1_LOJA)
dbSelectArea("SA6")
MSSeek(cFilial+SE1->E1_PORTADO)
dbSelectArea("SE1")

IF li > 58
cabec(titulo,cabec1,cabec2,nomeprog,tamanho,GetMv("MV_COMP"))
EndIF

If mv_par19 == 1
@li, 0 PSAY SE1->E1_CLIENTE
@li, 7 PSAY SubStr( SE1->E1_NOMCLI, 1, 20 )
@li, 28 PSAY SE1->E1_PREFIXO+"-"+SE1->E1_NUM+"-"+SE1->E1_PARCELA
@li, 47 PSAY SE1->E1_TIPO
@li, 51 PSAY SE1->E1_NATUREZ
@li, 62 PSAY SE1->E1_EMISSAO
@li, 73 PSAY SE1->E1_VENCTO
@li, 84 PSAY SE1->E1_VENCREA
@li, 95 PSAY SE1->E1_PORTADO+" "+SE1->E1_SITUACA
@li,101 PSAY xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1->E1_EMISSAO)
Picture tm ( SE1->E1_VALOR, 14 )
Endif

If dDataBase > E1_VENCREA //vencidos


Programação SQL com SIGA Advanced / AP5

If mv_par19 == 1
@li, 116 PSAY nSaldo Picture tm ( nSaldo, 14 )
EndIf
nJuros:=0
fa070Juros(mv_par15)
dbSelectArea("SE1")
If mv_par19 == 1
@li,133 PSAY nSaldo+nJuros Picture tm(nSaldo+nJuros,14)
EndIf
If SE1->E1_TIPO $ "RA /"+MV_CRNEG
nTit0 -= xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1-
>E1_EMISSAO)
nTit1 -= (nSaldo)
nTit2 -= (nSaldo+nJuros)
nMesTit0 -= xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1-
>E1_EMISSAO)
nMesTit1 -= (nSaldo)
nMesTit2 -= (nSaldo+nJuros)
Else
nTit0 += xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1-
>E1_EMISSAO)
nTit1 += (nSaldo)
nTit2 += (nSaldo+nJuros)
nMesTit0 += xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1-
>E1_EMISSAO)
nMesTit1 += (nSaldo)
nMesTit2 += (nSaldo+nJuros)
Endif
nTotJur += nJuros
nMesTitj += nJuros
nTotFilJ += nJuros
Else //a vencer
If mv_par19 == 1
@li,149 PSAY nSaldo Picture tm ( nSaldo, 14 )
EndIf
If ! ( SE1->E1_TIPO $ "RA /"+MV_CRNEG)
nTit0 += xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1-
>E1_EMISSAO)
nTit3 += (nSaldo-nTotAbat)
nTit4 += (nSaldo-nTotAbat)
nMesTit0 += xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1-
>E1_EMISSAO)
nMesTit3 += (nSaldo-nTotAbat)
nMesTit4 += (nSaldo-nTotAbat)
Else
nTit0 -= xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1-
>E1_EMISSAO)
nTit3 -= (nSaldo-nTotAbat)
nTit4 -= (nSaldo-nTotAbat)
nMesTit0 -= xMoeda(SE1->E1_VALOR,SE1->E1_MOEDA,mv_par15,SE1-
>E1_EMISSAO)
nMesTit3 -= (nSaldo-nTotAbat)
nMesTit4 -= (nSaldo-nTotAbat)
Endif
Endif

If mv_par19 == 1
@ li, 166 PSAY SE1->E1_NUMBCO
EndIf
If nJuros > 0
If mv_par19 == 1
@ Li,177 PSAY nJuros Picture Tm(nJuros,12)
EndIf
nJuros := 0
Endif

IF dDataBase > SE1->E1_VENCREA


nAtraso:=dDataBase-SE1->E1_VENCTO
IF Dow(SE1->E1_VENCTO) == 1 .Or. Dow(SE1->E1_VENCTO) == 7
IF Dow(dBaixa) == 2 .and. nAtraso <= 2
Programação SQL com SIGA Advanced / AP5

nAtraso := 0
EndIF
EndIF
nAtraso:=IIF(nAtraso<0,0,nAtraso)
IF nAtraso>0
If mv_par19 == 1
@li ,193 PSAY nAtraso Picture "9999"
EndIf
EndIF
EndIF
If mv_par19 == 1
@li,198 PSAY SubStr(SE1->E1_HIST,1,20)+ ;
IIF(E1_TIPO=="PR ","*"," ")+ ;
Iif(nSaldo == xMoeda(E1_VALOR,E1_MOEDA,mv_par15,dDataReaj)," ","P")
EndIf

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Carrega data do registro para permitir ³
//³ posterior an lise de quebra por mes. ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
dDataAnt := Iif(nOrdem == 6, SE1->E1_EMISSAO, SE1->E1_VENCREA)
dbSkip()
nTotTit ++
nMesTTit ++
nTotFiltit++
nTit5 ++
If mv_par19 == 1
li++
EndIf
Enddo

IF nTit5 > 0 .and. nOrdem != 2


SubTot130(nTit0,nTit1,nTit2,nTit3,nTit4,nOrdem,cCarAnt,nTotJur)
If mv_par19 == 1
Li++
EndIf
Endif

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Verifica quebra por mˆs ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
lQuebra := .F.
If nOrdem == 4 .and. Month(SE1->E1_VENCREA) # Month(dDataAnt)
lQuebra := .T.
Elseif nOrdem == 6 .and. Month(SE1->E1_EMISSAO) # Month(dDataAnt)
lQuebra := .T.
Endif
If lQuebra .and. nMesTTit # 0
ImpMes130(nMesTit0,nMesTit1,nMesTit2,nMesTit3,nMesTit4,nMesTTit,nMesTitJ)
nMesTit1 := nMesTit2 := nMesTit3 := nMesTit4 := nMesTTit := nMesTitj := 0
Endif
nTot0+=nTit0
nTot1+=nTit1
nTot2+=nTit2
nTot3+=nTit3
nTot4+=nTit4
nTotJ+=nTotJur

nTotFil0+=nTit0
nTotFil1+=nTit1
nTotFil2+=nTit2
nTotFil3+=nTit3
nTotFil4+=nTit4
Store 0 To nTit0,nTit1,nTit2,nTit3,nTit4,nTit5,nTotJur,nTotAbat
Enddo

dbSelectArea("SE1") // voltar para alias existente, se nao, nao funciona

//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Imprimir TOTAL por filial somente quan-³
Programação SQL com SIGA Advanced / AP5

//³ do houver mais do que 1 filial. ³


//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
if mv_par21 == 1 .and. SM0->(Reccount()) > 1
ImpFil130(nTotFil0,nTotFil1,nTotFil2,nTotFil3,nTotFil4,nTotFiltit,nTotFilJ)
Endif
Store 0 To nTotFil0,nTotFil1,nTotFil2,nTotFil3,nTotFil4,nTotFilTit,nTotFilJ
If Empty(xFilial("SE1"))
Exit
Endif

#IFDEF TOP
if TcSrvType() != "AS/400"
dbSelectArea("SE1")
dbCloseArea()
ChKFile("SE1")
dbSelectArea("SE1")
dbSetOrder(1)
endif
#ENDIF

dbSelectArea("SM0")
dbSkip()
Enddo

IF li != 80
IF li > 58
cabec(titulo,cabec1,cabec2,nomeprog,tamanho,GetMv("MV_COMP"))
EndIF
TotGer130(nTot0,nTot1,nTot2,nTot3,nTot4,nTotTit,nTotJ)
Roda(cbcont,cbtxt,"G")
EndIF

Set Device To Screen

#IFNDEF TOP
dbSelectArea("SE1")
dbClearFil(NIL)
RetIndex( "SE1" )
If !Empty(cIndexSE1)
FErase (cIndexSE1+OrdBagExt())
Endif
dbSetOrder(1)
#ELSE
if TcSrvType() != "AS/400"
dbSelectArea("SE1")
dbCloseArea()
ChKFile("SE1")
dbSelectArea("SE1")
dbSetOrder(1)
else
dbSelectArea("SE1")
dbClearFil(NIL)
RetIndex( "SE1" )
If !Empty(cIndexSE1)
FErase (cIndexSE1+OrdBagExt())
Endif
dbSetOrder(1)
endif
#ENDIF
If aReturn[5] = 1
Set Printer TO
dbCommitAll()
Ourspool(wnrel)
Endif
MS_FLUSH()
Return
Programação SQL com SIGA Advanced / AP5

Parte do Programa RDMAKE para execução de Query’s

//³Funcao ³ R170IMP
//³Descricao ³ Chamada do Relatorio
//³ Uso ³ MATR170

Function R170Imp
dbSelectArea("SE2")
dbSetOrder(8)
cQuery := "SELECT E2_NATUREZ, E2_VENCREA, E2_NOMFOR, E2_PREFIXO, "
cQuery := cQuery + " E2_NUM, E2_PARCELA, E2_VENCTO, E2_FORNECE, E2_LOJA,"
cQuery := cQuery + " E2_VALOR, E2_SALDO, E2_TIPO, E2_BAIXA, E2_EMISSAO"
cQuery := cQuery + ‘ FROM RetSqlName("SE1") ‘
cQuery := cQuery + " WHERE E2_FILIAL = '" + xFilial("SE2") + "'"
cQuery := cQuery + " AND D_E_L_E_T_ = ' ' "
cQuery := cQuery + " AND E2_NATUREZ >= '"+ MV_PAR01 +"' AND E2_NATUREZ <= '"+mv_par02+"'"
cQuery := cQuery + " AND E2_VENCREA >= '"+DTOS(mv_par03)+"' AND E2_VENCREA <= '"+DTOS(mv_par04)+"'"
cQuery := cQuery + " AND E2_FORNECE >= '"+mv_par07+"' And E2_FORNECE <= '"+mv_par08+"'"
cQuery := cQuery + " AND E2_EMISSAO >= '"+DTOS(mv_par09)+"' AND E2_EMISSAO <= '"+DTOS(mv_par10)+"'"
cQuery := cQuery + " AND E2_TIPO <> 'AB-'"
cQuery := cQuery + " ORDER BY E2_NATUREZ, E2_VENCREA, E2_NOMFOR"

cQuery := ChangeQuery(cQuery)

TCQUERY cQuery Alias TRB New


dbSelectArea("TRB")
nCont := 0
SetRegua(15000)
//ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
//³ Faz manualmente porque nao chama a funcao Cabec() ³
//ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
_nTotGer := 0
li := 60
cabec(titulo,cabec1,cabec2,nomeprog,tamanho,1)
li := 06

While !Eof()

IncRegua()

If li >56
cabec(titulo,cabec1,cabec2,nomeprog,tamanho,1)
End
_cNatur :=TRB->E2_NATUREZ
dbSelectArea("SED")
dbSetOrder(1)
dbSeek(xFilial() + _cNatur)
_cDescNat := SED->ED_DESCRIC
li := li + 1
@ li, 001 PSAY "Natureza..: "+AllTrim(_cNatur) + " - " + _cDescNat
li := li + 2
dbSelectArea("TRB")
_nTotNat := 0

While !Eof() .And. TRB->E2_NATUREZ == _cNatur

// Loop por Data


_dVenc := TRB->E2_VENCREA
_nTotDia := 0

While !Eof() .And. TRB->E2_VENCREA == _dVenc .And. ;


TRB->E2_NATUREZ == _cNatur
IncRegua()
Programação SQL com SIGA Advanced / AP5

IF !Empty(TRB->E2_BAIXA) .and. TRB->E2_BAIXA <= DTOS(dDataBase) .and.;


TRB->E2_SALDO == 0
dbSkip()
Loop
EndIF

nAbatimentos:= 0
_nTotAbat := 0
nSaldo := 0
_nSaldoT := 0

_nTotAbat:= nAbatimentos
// ------------------------ Calcula o Saldo ----------------------//
fSaldoTit()
_nSaldoT := nSaldo
_nValor := _nSaldoT - _nTotAbat

//----------------------------------------------------//
If _nValor <= 0
dbSelectArea("TRB")
dbSkip()
Loop
End
//--------------------------- Imprime ---------------------//
dbSelectArea("SA2")
dbSetOrder(1)
dbSeek(xFilial() + TRB->E2_FORNECE + TRB->E2_LOJA)
dbSelectArea("TRB")
@ li, 001 PSAY TRB->E2_FORNECE
@ li, 008 PSAY SUBSTR(SA2->A2_NOME,1,20)
@ li, 029 PSAY TRB->E2_PREFIXO
@ li, 033 PSAY TRB->E2_NUM
@ li, 040 PSAY TRB->E2_PARCELA
@ li, 042 PSAY TRB->E2_TIPO
@ li, 045 PSAY SUBST(TRB->E2_EMISSAO,7,2)+"/"+SUBST(TRB-
>E2_EMISSAO,5,2)+"/"+SUBST(TRB->E2_EMISSAO,3,2)
@ li, 055 PSAY SUBST(TRB->E2_VENCREA,7,2)+"/"+SUBST(TRB-
>E2_VENCREA,5,2)+"/"+SUBST(TRB->E2_VENCREA,3,2)
@ li, 064 PSAY _nValor Picture"@E 9,999,999.99"
@ li, 078 PSAY Iif((Val(Dtos(DDATABASE))-Val(TRB-
>E2_VENCREA))<=0,0,Val(Dtos(DDATABASE))-Val(TRB->E2_VENCREA)) Picture"@R 999"
_nTotDia := _nTotDia + _nValor
dbSkip()
li := li + 1
If li >56
cabec(titulo,cabec1,cabec2,nomeprog,tamanho,1)
li := li + 1
@ li, 001 PSAY "Natureza..: "+AllTrim(_cNatur) + " - " + SED->ED_DESCRIC + "
(continuacao)"
li := li + 2
End
End
If _nTotDia > 0
li := li + 1
@ li, 010 PSAY "Total do Dia.....: "
@ li, 064 PSAY _nTotDia Picture"@E 9,999,999.99"
li := li + 2
_nTotNat := _nTotNat + _nTotDia
Endif
End
li := li + 3
@ li, 010 PSAY "Tot.Natureza " + AllTrim(_cNatur) + " - " + AllTrim(_cDescNat)
@ li, 064 PSAY _nTotNat Picture"@E 9,999,999.99"
_nTotGer := _nTotGer + _nTotNat
li := 58
End
@ li, 010 PSAY "Total do Relatorio..:"
@ li, 062 PSAY _nTotGer Picture"@E 999,999,999.99"
Programação SQL com SIGA Advanced / AP5

EJECT

dbSelectArea("TRB")
dbCloseArea()
RetIndex("SE2")
dbSetOrder(1)
Set device to Screen
If aReturn[5] == 1
Set Printer TO
dbcommitAll()
ourspool(wnrel)
Endif
MS_FLUSH()
__Return()
Programação SQL com SIGA Advanced / AP5

7.2. Função ChangeQuery , SQLOrder e RetSQLName

A função Changequery deve sempre ser executada antes de enviar uma query ao
servidor, esta função tem como objetivo retornar a query modificada de acordo a melhorar
forma possível de escrita para cada banco de dados, portanto para ela ser utilizada você
deve utilizar o padrão ANSI de escrita, para depois a função ChangeQuery colocar o
código específico de cada Banco de Dados.

A Função SQLOrder tem o objetivo de retornar uma chave de índice de uma determinada
tabela no formato padrão para a utilização da clausula Order By, ou seja, o retorno da
função indexkey(), retorno um chave por exemplo igual a
(E1_FILIAL+E1_PREFIXO+E1_NUM+...), após execução desta função ele modifica para
(E1_FILIAL,E1_PREFIXO,E1_NUM,...) para campos que contituem funções DTOS e STR
também serão ajustados.

A função RetSQLName tem o objetivo de retornar o nome da tabela que se encontra na


tabela SX2.

7.3. Stored Procedures

Função do Programa fonte onde é disparada a Stored Procedure


//³Funca ³A330Inicia
//³Descricao ³ Pega valores do inicio do periodo para serem reprocessados ³±±
//³ Uso ³ MATA330 ³±±

STATIC Function A330Inicia()


#IFDEF TOP
Local cXFIlial,aResult
IF !lCusFIFO .and. ExistProc('A330INI')
cxFilial := BuildStrFil("SD1,SD2,SD3,SF4,SB9,SF5,SB2,SC2")
aResult := TCSPExec( xProcedures('A330INI'), cxFilial, Dtos(dINICIO),"@@",;
GetMv("MV_LOCPROC"), cFilAnt,;
Substr(cUsuario,7,15), DTOS(dDataBase))

IF Len(aResult) = 0 .or. aResult[1] == "0"


Final("Probs. SP. A330INI")
Endif
Else
Xa330Inicia()
Endif
Return Nil

Static Function Xa330Inicia()


#ENDIF
LOCAL nV,nX,bBloco:={ |nV,nX| Trim(nV)+STR(nX,1) }
LOCAL aSaldoIni[07],cProduto:="",cLocal:=""
LOCAL aSaldoFF[05]

… Continuação da função padrão para quando não houver Stored Procedure


Programação SQL com SIGA Advanced / AP5

-- SQLParse - Microsiga Software SA


-- Processado em 19/4/2000 09:36:15
-- Dialeto: MSSql 6.5
--------------------------------------
-- Criacao de procedure
CREATE PROCEDURE A330INI_99 (
@IN_XFILIAL VARCHAR( 255 ) ,
@IN_DINICIO VARCHAR( 8 ) ,
@IN_CFILAUX VARCHAR( 02 ) ,
@IN_MV_LOCPROC VARCHAR( 02 ) ,
@IN_FILIALCOR VARCHAR( 02 ) ,
@IN_USER_LG VARCHAR( 17 ) ,
@IN_DATABASE VARCHAR( 08 ) ,
@OUT_RESULTADO VARCHAR( 1 ) output ) WITH ENCRYPTION AS

-- Declaracoes de variaveis
DECLARE @cCod VARCHAR( 15 )
DECLARE @cLocal VARCHAR( 02 )
DECLARE @nRecno INTEGER
DECLARE @nQSALDOATU FLOAT
DECLARE @nCUSTOATU FLOAT
DECLARE @nCUSTOATU2 FLOAT
DECLARE @nCUSTOATU3 FLOAT
DECLARE @nCUSTOATU4 FLOAT
DECLARE @nCUSTOATU5 FLOAT
DECLARE @nQTSEGUM FLOAT
DECLARE @cFil_SB2 VARCHAR( 02 )
DECLARE @cFil_SC2 VARCHAR( 02 )
DECLARE @nRec INTEGER
DECLARE @nRecAnt INTEGER
DECLARE @nMaxRecnoSC2 INTEGER
DECLARE @cFILAUX VARCHAR( 02 )
BEGIN
SELECT @OUT_RESULTADO = '0'
SELECT @cFILAUX = @IN_CFILAUX
IF @cFILAUX is null
BEGIN
SELECT @cFILAUX = ' '
END
IF SUBSTRING ( @IN_XFILIAL , 7 , 1 ) = 'C'
BEGIN
SELECT @cFil_SB2 = ' '
END
ELSE
BEGIN
SELECT @cFil_SB2 = @IN_FILIALCOR
END
IF SUBSTRING ( @IN_XFILIAL , 8 , 1 ) = 'C'
BEGIN
SELECT @cFil_SC2 = ' '
END
ELSE
BEGIN
SELECT @cFil_SC2 = @IN_FILIALCOR
END

-- Declaracao do cursor CUR_A330INI


DECLARE CUR_A330INI INSENSITIVE CURSOR FOR
SELECT B2_COD , B2_LOCAL , R_E_C_N_O_
FROM SB2990
WHERE B2_FILIAL = @cFil_SB2 and B2_COD not like 'MOD%' and D_E_L_E_T_ <> '*'
FOR READ ONLY
OPEN CUR_A330INI
FETCH CUR_A330INI
INTO @cCod , @cLocal , @nRecno
WHILE ( (@@fetch_status = 0 ) )
BEGIN
Programação SQL com SIGA Advanced / AP5

EXEC MTXFUN1_99 @IN_XFILIAL , @cCod , @cLocal , @IN_DINICIO , @cFILAUX , @IN_MV_LOCPROC , @IN_FILIALCOR


, @IN_USER_LG ,
@IN_DATABASE , @nQSALDOATU output , @nCUSTOATU output , @nCUSTOATU2 output , @nCUSTOATU3 output ,
@nCUSTOATU4 output ,
@nCUSTOATU5 output , @nQTSEGUM output
IF @nQSALDOATU > 0
BEGIN
UPDATE SB2990
SET B2_QFIM = @nQSALDOATU , B2_VFIM1 = @nCUSTOATU , B2_VFIM2 = @nCUSTOATU2 , B2_VFIM3 =
@nCUSTOATU3 , B2_VFIM4 = @nCUSTOATU4
, B2_VFIM5 = @nCUSTOATU5 , B2_CM1 = @nCUSTOATU / @nQSALDOATU , B2_CM2 = @nCUSTOATU2 /
@nQSALDOATU , B2_CM3 = @nCUSTOATU3 / @nQSALDOATU
, B2_CM4 = @nCUSTOATU4 / @nQSALDOATU , B2_CM5 = @nCUSTOATU5 / @nQSALDOATU
WHERE R_E_C_N_O_ = @nRecno
END
ELSE
BEGIN
UPDATE SB2990
SET B2_QFIM = @nQSALDOATU , B2_VFIM1 = @nCUSTOATU , B2_VFIM2 = @nCUSTOATU2 , B2_VFIM3 =
@nCUSTOATU3 , B2_VFIM4 = @nCUSTOATU4
, B2_VFIM5 = @nCUSTOATU5
WHERE R_E_C_N_O_ = @nRecno
END
FETCH CUR_A330INI
INTO @cCod , @cLocal , @nRecno
END
CLOSE CUR_A330INI
DEALLOCATE CUR_A330INI
SELECT @nMaxRecnoSC2 = MAX ( R_E_C_N_O_ )
FROM SC2990
WHERE C2_FILIAL = @cFil_SC2
IF @nMaxRecnoSC2 is null
BEGIN
SELECT @nMaxRecnoSC2 = 0
END
SELECT @nRec = 0
WHILE (@nRec <= @nMaxRecnoSC2 )
BEGIN
SELECT @nRecAnt = @nRec
SELECT @nRec = @nRec + 1024
UPDATE SC2990
SET C2_VFIM1 = C2_VINI1 , C2_VFIM2 = C2_VINI2 , C2_VFIM3 = C2_VINI3 , C2_VFIM4 = C2_VINI4 , C2_VFIM5 =
C2_VINI5
, C2_APRFIM1 = C2_APRINI1 , C2_APRFIM2 = C2_APRINI2 , C2_APRFIM3 = C2_APRINI3 , C2_APRFIM4 =
C2_APRINI4 , C2_APRFIM5 = C2_APRINI5

WHERE R_E_C_N_O_ > @nRecAnt and R_E_C_N_O_ <= @nRec and C2_FILIAL = @cFil_SC2
END
SELECT @OUT_RESULTADO = '1'
END
GO
Programação SQL com SIGA Advanced / AP5

--------------------------------------
-- SQLParse - Microsiga Software SA
-- Processado em 19/4/2000 09:36:16
-- Dialeto: MSSql 7.0
--------------------------------------
-- Criacao de procedure
CREATE PROCEDURE A330INI_99 (
@IN_XFILIAL VarChar( 255 ) ,
@IN_DINICIO VarChar( 8 ) ,
@IN_CFILAUX VarChar( 02 ) ,
@IN_MV_LOCPROC VarChar( 02 ) ,
@IN_FILIALCOR VarChar( 02 ) ,
@IN_USER_LG VarChar( 17 ) ,
@IN_DATABASE VarChar( 08 ) ,
@OUT_RESULTADO VarChar( 1 ) output )

WITH ENCRYPTION AS

-- Declaracoes de variaveis
DECLARE @cCod VarChar( 15 )
DECLARE @cLocal VarChar( 02 )
DECLARE @nRecno Integer
DECLARE @nQSALDOATU Float
DECLARE @nCUSTOATU Float
DECLARE @nCUSTOATU2 Float
DECLARE @nCUSTOATU3 Float
DECLARE @nCUSTOATU4 Float
DECLARE @nCUSTOATU5 Float
DECLARE @nQTSEGUM Float
DECLARE @cFil_SB2 VarChar( 02 )
DECLARE @cFil_SC2 VarChar( 02 )
DECLARE @nRec Integer
DECLARE @nRecAnt Integer
DECLARE @nMaxRecnoSC2 Integer
DECLARE @cFILAUX VarChar( 02 )
BEGIN
SET @OUT_RESULTADO = '0'
SET @cFILAUX = @IN_CFILAUX
IF @cFILAUX is null
BEGIN
SET @cFILAUX = ' '
END
IF SUBSTRING ( @IN_XFILIAL , 7 , 1 ) = 'C'
BEGIN
SET @cFil_SB2 = ' '
END
ELSE
BEGIN
SET @cFil_SB2 = @IN_FILIALCOR
END
IF SUBSTRING ( @IN_XFILIAL , 8 , 1 ) = 'C'
BEGIN
SET @cFil_SC2 = ' '
END
ELSE
BEGIN
SET @cFil_SC2 = @IN_FILIALCOR
END

-- Declaracao do cursor CUR_A330INI


DECLARE CUR_A330INI INSENSITIVE CURSOR FOR
SELECT B2_COD , B2_LOCAL , R_E_C_N_O_
FROM SB2990
WHERE B2_FILIAL = @cFil_SB2 and B2_COD not like 'MOD%' and D_E_L_E_T_ <> '*'
FOR READ ONLY

OPEN CUR_A330INI
FETCH CUR_A330INI
INTO @cCod , @cLocal , @nRecno
Programação SQL com SIGA Advanced / AP5

WHILE ( (@@fetch_status = 0 ) )
BEGIN
EXEC MTXFUN1_99 @IN_XFILIAL , @cCod , @cLocal , @IN_DINICIO , @cFILAUX , @IN_MV_LOCPROC , @IN_FILIALCOR
, @IN_USER_LG ,
@IN_DATABASE , @nQSALDOATU output , @nCUSTOATU output , @nCUSTOATU2 output , @nCUSTOATU3 output ,
@nCUSTOATU4 output ,
@nCUSTOATU5 output , @nQTSEGUM output
IF @nQSALDOATU > 0
BEGIN
UPDATE SB2990
WITH (ROWLOCK)
SET B2_QFIM = @nQSALDOATU , B2_VFIM1 = @nCUSTOATU , B2_VFIM2 = @nCUSTOATU2 , B2_VFIM3 =
@nCUSTOATU3 , B2_VFIM4 = @nCUSTOATU4
, B2_VFIM5 = @nCUSTOATU5 , B2_CM1 = @nCUSTOATU / @nQSALDOATU , B2_CM2 = @nCUSTOATU2 /
@nQSALDOATU , B2_CM3 = @nCUSTOATU3 / @nQSALDOATU
, B2_CM4 = @nCUSTOATU4 / @nQSALDOATU , B2_CM5 = @nCUSTOATU5 / @nQSALDOATU
WHERE R_E_C_N_O_ = @nRecno
END
ELSE
BEGIN
UPDATE SB2990
WITH (ROWLOCK)
SET B2_QFIM = @nQSALDOATU , B2_VFIM1 = @nCUSTOATU , B2_VFIM2 = @nCUSTOATU2 , B2_VFIM3 =
@nCUSTOATU3 , B2_VFIM4 = @nCUSTOATU4
, B2_VFIM5 = @nCUSTOATU5
WHERE R_E_C_N_O_ = @nRecno
END
FETCH CUR_A330INI
INTO @cCod , @cLocal , @nRecno
END
CLOSE CUR_A330INI
DEALLOCATE CUR_A330INI
SELECT @nMaxRecnoSC2 = MAX ( R_E_C_N_O_ )
FROM SC2990
WHERE C2_FILIAL = @cFil_SC2
IF @nMaxRecnoSC2 is null
BEGIN
SET @nMaxRecnoSC2 = 0
END
SET @nRec = 0
WHILE (@nRec <= @nMaxRecnoSC2 )
BEGIN
SET @nRecAnt = @nRec
SET @nRec = @nRec + 1024
UPDATE SC2990
WITH (ROWLOCK)
SET C2_VFIM1 = C2_VINI1 , C2_VFIM2 = C2_VINI2 , C2_VFIM3 = C2_VINI3 , C2_VFIM4 = C2_VINI4 , C2_VFIM5 =
C2_VINI5
, C2_APRFIM1 = C2_APRINI1 , C2_APRFIM2 = C2_APRINI2 , C2_APRFIM3 = C2_APRINI3 , C2_APRFIM4 =
C2_APRINI4 , C2_APRFIM5 = C2_APRINI5

WHERE R_E_C_N_O_ > @nRecAnt and R_E_C_N_O_ <= @nRec and C2_FILIAL = @cFil_SC2
END
SET @OUT_RESULTADO = '1'
END
GO
Programação SQL com SIGA Advanced / AP5

--------------------------------------
-- SQLParse - Microsiga Software SA
-- Processado em 19/4/2000 09:36:16
-- Dialeto: Oracle
--------------------------------------
-- Criacao de procedure
CREATE OR REPLACE PROCEDURE A330INI_99 (
IN_XFILIAL in VARCHAR ,
IN_DINICIO in VARCHAR ,
IN_CFILAUX in VARCHAR ,
IN_MV_LOCPROC in VARCHAR ,
IN_FILIALCOR in VARCHAR ,
IN_USER_LG in VARCHAR ,
IN_DATABASE in VARCHAR ,
OUT_RESULTADO out VARCHAR ) IS

-- Declaracoes de variaveis
vcCod VARCHAR( 15 ) ;
vcLocal VARCHAR( 02 ) ;
vnRecno INTEGER ;
vnQSALDOATU FLOAT ;
vnCUSTOATU FLOAT ;
vnCUSTOATU2 FLOAT ;
vnCUSTOATU3 FLOAT ;
vnCUSTOATU4 FLOAT ;
vnCUSTOATU5 FLOAT ;
vnQTSEGUM FLOAT ;
vcFil_SB2 VARCHAR( 02 ) ;
vcFil_SC2 VARCHAR( 02 ) ;
vnRec INTEGER ;
vnRecAnt INTEGER ;
vnMaxRecnoSC2 INTEGER ;
vcFILAUX VARCHAR( 02 ) ;

-- Declaracao do cursor CUR_A330INI


CURSOR CUR_A330INI IS
SELECT B2_COD , B2_LOCAL , R_E_C_N_O_
FROM SB2990
WHERE B2_FILIAL = vcFil_SB2 and B2_COD not like 'MOD%' and D_E_L_E_T_ <> '*' ;

BEGIN
OUT_RESULTADO := '0' ;
vcFILAUX := IN_CFILAUX ;
IF vcFILAUX is null THEN
vcFILAUX := ' ' ;
END IF;
IF SUBSTR ( IN_XFILIAL , 7 , 1 ) = 'C' THEN
vcFil_SB2 := ' ' ;
ELSE
vcFil_SB2 := IN_FILIALCOR ;
END IF;
IF SUBSTR ( IN_XFILIAL , 8 , 1 ) = 'C' THEN
vcFil_SC2 := ' ' ;
ELSE
vcFil_SC2 := IN_FILIALCOR ;
END IF;
OPEN CUR_A330INI;
FETCH CUR_A330INI
INTO vcCod , vcLocal , vnRecno ;
<<parse5>>
WHILE ( (CUR_A330INI%FOUND ) ) LOOP
MTXFUN1_99 (IN_XFILIAL , vcCod , vcLocal , IN_DINICIO , vcFILAUX , IN_MV_LOCPROC , IN_FILIALCOR , IN_USER_LG ,
IN_DATABASE ,
vnQSALDOATU , vnCUSTOATU , vnCUSTOATU2 , vnCUSTOATU3 , vnCUSTOATU4 , vnCUSTOATU5 , vnQTSEGUM );
IF vnQSALDOATU > 0 THEN
Programação SQL com SIGA Advanced / AP5

UPDATE SB2990
SET B2_QFIM = vnQSALDOATU , B2_VFIM1 = vnCUSTOATU , B2_VFIM2 = vnCUSTOATU2 , B2_VFIM3 =
vnCUSTOATU3 , B2_VFIM4 = vnCUSTOATU4
, B2_VFIM5 = vnCUSTOATU5 , B2_CM1 = vnCUSTOATU / vnQSALDOATU , B2_CM2 = vnCUSTOATU2 /
vnQSALDOATU ,
B2_CM3 = vnCUSTOATU3 / vnQSALDOATU , B2_CM4 = vnCUSTOATU4 / vnQSALDOATU , B2_CM5 =
vnCUSTOATU5 / vnQSALDOATU

WHERE R_E_C_N_O_ = vnRecno ;


ELSE
UPDATE SB2990
SET B2_QFIM = vnQSALDOATU , B2_VFIM1 = vnCUSTOATU , B2_VFIM2 = vnCUSTOATU2 , B2_VFIM3 =
vnCUSTOATU3 , B2_VFIM4 = vnCUSTOATU4
, B2_VFIM5 = vnCUSTOATU5
WHERE R_E_C_N_O_ = vnRecno ;
END IF;
FETCH CUR_A330INI
INTO vcCod , vcLocal , vnRecno ;
END LOOP;
CLOSE CUR_A330INI;
BEGIN
SELECT MAX ( R_E_C_N_O_ )
INTO vnMaxRecnoSC2
FROM SC2990
WHERE C2_FILIAL = vcFil_SC2 ;
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL;
END;
IF vnMaxRecnoSC2 is null THEN
vnMaxRecnoSC2 := 0 ;
END IF;
vnRec := 0 ;
<<parse6>>
WHILE (vnRec <= vnMaxRecnoSC2 ) LOOP
vnRecAnt := vnRec ;
vnRec := vnRec + 1024 ;
UPDATE SC2990
SET C2_VFIM1 = C2_VINI1 , C2_VFIM2 = C2_VINI2 , C2_VFIM3 = C2_VINI3 , C2_VFIM4 = C2_VINI4 , C2_VFIM5 =
C2_VINI5
, C2_APRFIM1 = C2_APRINI1 , C2_APRFIM2 = C2_APRINI2 , C2_APRFIM3 = C2_APRINI3 , C2_APRFIM4 =
C2_APRINI4
, C2_APRFIM5 = C2_APRINI5
WHERE R_E_C_N_O_ > vnRecAnt and R_E_C_N_O_ <= vnRec and C2_FILIAL = vcFil_SC2 ;
END LOOP;
OUT_RESULTADO := '1' ;
END;
Programação SQL com SIGA Advanced / AP5

--------------------------------------
-- SQLParse - Microsiga Software SA
-- Processado em 19/4/2000 09:36:16
-- Dialeto: Informix
--------------------------------------
-- Criacao de procedure
CREATE PROCEDURE A330INI_99 (
IN_XFILIAL VARCHAR( 255 ) ,
IN_DINICIO VARCHAR( 8 ) ,
IN_CFILAUX VARCHAR( 02 ) ,
IN_MV_LOCPROC VARCHAR( 02 ) ,
IN_FILIALCOR VARCHAR( 02 ) ,
IN_USER_LG VARCHAR( 17 ) ,
IN_DATABASE VARCHAR( 08 ) ,
OUT_RESULTADO VARCHAR( 1 ) )

Returning VARCHAR( 1 ) ;
-- Declaracoes de variaveis

DEFINE vcCod VARCHAR( 15 ) ;


DEFINE vcLocal VARCHAR( 02 ) ;
DEFINE vnRecno INTEGER ;
DEFINE vnQSALDOATU FLOAT ;
DEFINE vnCUSTOATU FLOAT ;
DEFINE vnCUSTOATU2 FLOAT ;
DEFINE vnCUSTOATU3 FLOAT ;
DEFINE vnCUSTOATU4 FLOAT ;
DEFINE vnCUSTOATU5 FLOAT ;
DEFINE vnQTSEGUM FLOAT ;
DEFINE vcFil_SB2 VARCHAR( 02 ) ;
DEFINE vcFil_SC2 VARCHAR( 02 ) ;
DEFINE vnRec INTEGER ;
DEFINE vnRecAnt INTEGER ;
DEFINE vnMaxRecnoSC2 INTEGER ;
DEFINE vcFILAUX VARCHAR( 02 ) ;
BEGIN
LET OUT_RESULTADO = '0' ;
LET vcFILAUX = IN_CFILAUX ;
IF vcFILAUX is null THEN
LET vcFILAUX = ' ' ;
END IF;
IF SUBSTR ( IN_XFILIAL , 7 , 1 ) = 'C' THEN
LET vcFil_SB2 = ' ' ;
ELSE
LET vcFil_SB2 = IN_FILIALCOR ;
END IF;
IF SUBSTR ( IN_XFILIAL , 8 , 1 ) = 'C' THEN
LET vcFil_SC2 = ' ' ;
ELSE
LET vcFil_SC2 = IN_FILIALCOR ;
END IF;
FOREACH CUR_A330INI WITH HOLD FOR
SELECT B2_COD , B2_LOCAL , R_E_C_N_O_
INTO vcCod , vcLocal , vnRecno
FROM SB2990
WHERE B2_FILIAL = vcFil_SB2 and B2_COD not like 'MOD%' and D_E_L_E_T_ <> '*'
CALL MTXFUN1_99 (IN_XFILIAL , vcCod , vcLocal , IN_DINICIO , vcFILAUX , IN_MV_LOCPROC , IN_FILIALCOR ,
IN_USER_LG ,
IN_DATABASE , vnQSALDOATU , vnCUSTOATU , vnCUSTOATU2 , vnCUSTOATU3 , vnCUSTOATU4 , vnCUSTOATU5 ,
vnQTSEGUM ) RETURNING vnQSALDOATU, vnCUSTOATU, vnCUSTOATU2, vnCUSTOATU3, vnCUSTOATU4, vnCUSTOATU5,
vnQTSEGUM;
IF vnQSALDOATU > 0 THEN
UPDATE SB2990
SET B2_QFIM = vnQSALDOATU , B2_VFIM1 = vnCUSTOATU , B2_VFIM2 = vnCUSTOATU2 , B2_VFIM3 =
vnCUSTOATU3 ,
B2_VFIM4 = vnCUSTOATU4 , B2_VFIM5 = vnCUSTOATU5 , B2_CM1 = vnCUSTOATU / vnQSALDOATU , B2_CM2
= vnCUSTOATU2 / vnQSALDOATU
, B2_CM3 = vnCUSTOATU3 / vnQSALDOATU , B2_CM4 = vnCUSTOATU4 / vnQSALDOATU , B2_CM5 =
Programação SQL com SIGA Advanced / AP5

vnCUSTOATU5 / vnQSALDOATU

WHERE R_E_C_N_O_ = vnRecno ;


ELSE
UPDATE SB2990
SET B2_QFIM = vnQSALDOATU , B2_VFIM1 = vnCUSTOATU , B2_VFIM2 = vnCUSTOATU2 , B2_VFIM3 =
vnCUSTOATU3 ,
B2_VFIM4 = vnCUSTOATU4 , B2_VFIM5 = vnCUSTOATU5
WHERE R_E_C_N_O_ = vnRecno ;
END IF;
CONTINUE FOREACH;
END FOREACH;
SELECT MAX ( R_E_C_N_O_ )
INTO vnMaxRecnoSC2
FROM SC2990
WHERE C2_FILIAL = vcFil_SC2 ;
IF vnMaxRecnoSC2 is null THEN
LET vnMaxRecnoSC2 = 0 ;
END IF;
LET vnRec = 0 ;
WHILE (vnRec <= vnMaxRecnoSC2 )
LET vnRecAnt = vnRec ;
LET vnRec = vnRec + 1024 ;
UPDATE SC2990
SET C2_VFIM1 = C2_VINI1 , C2_VFIM2 = C2_VINI2 , C2_VFIM3 = C2_VINI3 , C2_VFIM4 = C2_VINI4 , C2_VFIM5 =
C2_VINI5
, C2_APRFIM1 = C2_APRINI1 , C2_APRFIM2 = C2_APRINI2 , C2_APRFIM3 = C2_APRINI3 , C2_APRFIM4 =
C2_APRINI4
, C2_APRFIM5 = C2_APRINI5
WHERE R_E_C_N_O_ > vnRecAnt and R_E_C_N_O_ <= vnRec and C2_FILIAL = vcFil_SC2 ;
END WHILE
LET OUT_RESULTADO = '1' ;
Return OUT_RESULTADO;
END
END PROCEDURE;

7.4. Comandos DDL

São comandos do Administrador do Banco de dados, alguns destes comandos são muito
comuns no seu uso e são padronizados em todos os Bancos de Dados, em algum
momento eles serão muito úteis.

7.4.1.1. Truncate Table

Comando para remover todos as linhas de uma tabela sem utilizar a opção
de log do banco de dados esta função é similar ao conhecido ZAP no
Clipper ou um Open output no Cobol.

Exemplo: TRUNCATE TABLE SA1990

7.4.1.2. Drop Table

Remove a tabela do Banco de Dados e todos as suas dependências.

Exemplo: DROP TABLE SA1990

Potrebbero piacerti anche