Considerando isoladamente a extração de dados OVER é uma o mais interessante recurso incluído ao Firebird.

Há uma possibilidade grande de combinações onde OVER se aplica – não vamos conseguir cobrir tudo somente neste POST, então vamos nos concentrar a um texto já tratando neste blog em relação a versão 2.5, que é apresentação de RANK, ou seja, mostrar a posição que se encontra o dado dentro da lista..

Ex: Qual a posição do vendedor XXX no RANK de vendas;

A implementação segue um padrão de estrutura tratado como “analytical functions”, ou seja, funções analíticas ou de análise de dados.

A ideia é usar um SELECT para separar uma janela de dados em paralelo do mesmo dado e montar um relacionamento dos dados do SELECT com os dados da JANELA para efetuar algum cálculo… no caso, calcular o RANK.
Tomando o exemplo da documentação emprestado

[code language=”sql”]select id, salary,
dense_rank() over (order by salary),
rank() over (order by salary),
row_number() over (order by salary),
sum(1) over (order by salary)
from employee
order by salary;

The result set:
id salary dense_rank rank row_number sum
— —— ———- —- ———- —
3 8.00 1 1 1 1
4 9.00 2 2 2 2
1 10.00 3 3 3 4
5 10.00 3 3 4 4
2 12.00 4 5 5 5

[/code]

Fazendo uma leitura do exemplo, em primeiro passo o engine monta o SELECT – quando encontra o comando OVER, ele separa uma janela em paralelo com os dados do mesmo SELECT (agora tem 1 cópia do mesmo dado do SELECT)… o que vem depois do OVER (….) é a forma em que o dado será organizado – no exemplo ORDER BY Salary; Sobre a janela de dados aplica a função indicada – o RANK();

Pegando carona no exemplo:

Há uma diferença entre RANK() e DENSE_RANK(),  em relação a forma de sequencia montada quando existe repetição do dado… enquanto RANK() continua a contagem quando encontra repetições, no DENSE_RANK() o número é mantido e segue a mesma sequencia do número anterior.

ROW_NUMBER() é uma contagem simples de linhas sem diferenciar dados repetidos como faz o RANK();

 

 

 

Quando uma transação no banco de dados exigir uma avaliação de registros já existentes no banco para decidir se o que precisa fazer é um UPDATE ou um INSERT em geral exige no mínimo duas chamadas para o banco de dados… uma para fazer o SELECT (toma decisão sobre o comando a aplicar) e então envia outra chamada com um UPDATE ou com um INSERT;

Para otimizar estes passos é possível utilizar “MERGE” ou “UPDATE OR INSERT”. Quando o desejo é passar os dados de uma tabela para outro o MERGE pode ser o mais adequado para a operação, mas se deseja atualizar os dados com entradas de parâmetros, sem vincular a uma tabela, o mais adequado será usar o comando “UPDATE OR INSERT”.

 

  1. Usando MERGE para fazer INSERT OR UPDATE com um único comando com base em uma tabela

O comando MERGE permite submeter uma única chamada para o banco de dados, quando as condições “where” coinciderem executa um UPDATE se não coincidirem executa um INSERT;

Exemplo da documentação:

[code language=”sql”]
MERGE INTO customers c 
USING    (SELECT * FROM customers_delta WHERE id > 10) cd    
ON (c.id = cd.id) 
WHEN MATCHED THEN   
UPDATE SET name = cd.name 
WHEN NOT MATCHED THEN   
INSERT (id, name)    VALUES (cd.id, cd.name)
[/code]
No Firebird3, é possível utilizar DELETE também – ou seja, agora é possível utilizar UPDATE,INSERT ou DELETE;

No exemplo, para que funcione, há uma premissa básica que faz parte do MERGE… é obrigatório que “customers_delta” tenha pelo menos 1 linha… Se o resultado de “customers_delta” for nenhuma linha, NADA será feito (nem UPDATE nem INSERT)…
De outro lado, existindo pelo menos 1 linha em customers_delta, ocorrerá a comparação ON (c.id = cd.id)…  em encontrando o mesmo código “WHEN MATCHED” será executado o UPDATE… caso não encontre o código será efetuado o INSERT (WHEN NOT MATCHED)…

 

Avançando um pouco mais… digamos que queremos avaliar uma única tabela… assim:   procurar se no cadastro de produto existe um determinado código…. caso exista UPDATE, caso não exista INSERT…

Para que funcione, lembra da premissa básica – o SELECT de USING, é obrigatório retornar pelo menos 1 linha. Quando o código procurado existir, o UPDATE será executado com sucesso, mas…..   se não existir o código, o USING SELECT  quebra a premissa básica (não existe a linha) – com isto o INSERT não funciona.

Vamos fazer uma adaptação para que o MERGE funcione usando RDB$DATABASE (o que o deixa igual ao UPDATE OR INSERT)

Exemplo:
[code language=”sql”]
MERGE INTO fb_prod c
USING
(SELECT ‘999999’ codigo, ‘nome do produto’ nome FROM rdb$database) cd
ON (c.codigo = cd.codigo)
WHEN MATCHED THEN
UPDATE SET nome = cd.nome
WHEN NOT MATCHED THEN
INSERT (codigo, nome,id) VALUES (cd.codigo, cd.nome,1)
[/code]

2. Usando UPDATE OR INSERT :

Ao usar UPDATE OR INSERT não é necessário vincular o comando a uma tabela associada o que torna o comando mais flexível em relação ao MERGE… veja um exemplo de como fazer:
[code language=”sql”]
UPDATE OR INSERT INTO fb_prod (codigo, nome, id)
values (‘999998’, ‘nome usando update or insert’, 2)
MATCHING (codigo)

[/code]

Em resumo, cada situação há várias formas de fazer a mesma coisa… escolha a que for mais eficiente

No Firebird 3 passou a ser possível criar exception com parâmetros que adicionam texto à mensagem retornada para o usuário.

create exception e_invalid_val ‘Valor invalido @1  para a coluna @2’;


if (val < 1000) then
thing = val;
else

exception e_invalid_val using (val, ‘thing’);
end

 

Este recurso na prática não adiciona nenhum ganho, já que no 2.5 era possível adicionar um texto à exceção..

Exception erro ‘Valor invalido ‘||val||’ para a coluna xxxx’;

 

 

Quando um arquivo é gravado no disco, mesmo tendo 1 único byte, o disco aloca um espaço mínimo de 1 cluster ( o mais comum é 1 cluster = 4096 bytes);

Existem HDs que gravam número de bytes diferente para 1 cluster, dependendo do modelo e fabricante; Para saber qual o tamanho de 1 cluster no disco basta escrever uma arquivo TXT com 1 byte de conteúdo, ir na propriedade do arquivo (via explorer) e checar qual o tamanho em disco……

O que fazer com esta informação ?

O banco de dados firebird usa gravar os dados em páginas; Cada página tem uma quantidade de bytes que é gravado juntamento com o FDB conhecido como “Page size”. Se uma pagina for de 8192, por exemplo, e 1 cluster no HD for de 4096, significa que para cada página que o banco for gravar ele vai precisar de 2 clusters físicos no disco.  Mesmo quando 1 página tiver um número muito pequeno de bytes a serem gravados, mesmo assim, o HD vai utilizar 2 cluster.

Não é difícil imaginar que o FDB vai ficar bem grande, com muitos buracos vazios. Para adequar este comportamento, o tamanho do “Page Size” deve ser o mesmo tamanho de 1 cluster no HD, destar forma o comportamento do banco de dados será o mesmo que aquele que o HD que esta instalado.

Para alterar o “Page size” é necessário alterar o parâmetro durante o RESTORE do banco de dados incluindo a opção: F:4096 ( quando o HD usar cluster de 4096 );

Exemplo:

gbak -rep -F 4096 meubackup.fbk meubanco.fdb -user sysdba -pass masterkey

 

 

Depois de fazer uma leitura rápida da documentação do novo RC – partindo para instalação.

Instalei a versão WIN64 em uma máquina que já tinha tanto 3.0 RC1 quanto 2.5 rodando na 3051 (3) e o outro na 3050 (2.5).

No primeiro passo o instalador reclamou que já tinha uma instalação. Parei o serviço, apaguei a pasta do 3.0 para fazer uma instalação limpa. Ele reclama que já existe a pasta do 2.5, mas não há risco em continuar pois instala em uma sub-pasta diferente do 2.5

Durante o processo ele deixa escolher como vai rodar – se serviço ou app, bem como o tipo de instalação – escolhi SuperClassic (novo modo de funcionamento); No passo seguinte pergunta qual será o usuário administrador e senha – importante neste ponto, já que ao contrário do 2.5 ele não vem com o admin configurado e precisa fazer isto na instalação – neste momento informei o admin que todos já conhecem, em produção seria interessante definir um outro admin para fugir do padão conhecido por todos.

Concluído a instalação com tranquilidade, abri o “firebird.conf” para configurar a porta, já que vou continuar usando o 2.5 junto com o 3.0 – editei e alterei:  RemoteServicePort = 3051

No passo seguinte subi o serviço e vamos abrir um banco que já tinha rodando com 3.0 – primeiro instante não consegui logar, depois de alguns testes notei que agora o nome do usuário é sensível a maiúsculo e minúsculo, depois disto… foi… (revisão: o comportamento ocorreu usando o IBExpert (2016.12) – só aceitou maiúsculo – configurando direto no aplicativo delphi, funcionou tanto minúsculo como maúsculo – mensagem enviada pelo Cantú pelo facebook/firebird)

Caso escolha rodar como aplicativo (não serviço) 
é possível iniciar usando o comando:
<strong>       firebird -m -a</strong>

Como passar o 2.5 para 3.0:

Nas compilações anteriores foi preciso fazer backup do banco de produção usando o 2.5 e depois restaurar com o 3.0; Esta ação esta ligado a mudança de estrutura do banco assumindo nova versão no 3.0, creio que não será possível copiar direto;

Antes não era possível fazer backup usando o 3.0 de um banco do 2.5, não refiz o teste para verificar se esta restrição continua. Então naquela ocasião foi obrigatório fazer o backup do banco no 2.5  antes de instalar o 3.0;

Vamos para o IBExpert:

Aqui passei pelo necessidade de reconfigurar a FBClient.dll que no 3.0 não é compatível com a do 2.5, ou seja, precisei indicar para o IBExpert qual a DLL iria utilizar – usei a que vem na pasta WOW64 – não funcionou, ainda não chequei porque… peguei a FBClient.dll que já tinha da RC1 – foi… (revisando: fiz novos teste e a FBClient que esta no disco de instalação do RC2, funcionou)

Na RC1 não era possível usar a FBClient.dll da 3.0 para acessar a 2.5 – o contrário também não era possível… (revisão: novos testes mostraram que a FBClient que vem no disco da RC2 agora é compatível com 2.5 também, ou seja, pode utilizar a mesma DLL tanto para acesso ao 3.0 quanto para o 2.5)

 

Entramos, agora RC2 rodando.

 

O Firebird 3 mudou algumas coisas em relação a forma de funcionamento do servidor;

Agora temos as seguintes possibilidades de instalação:

  1. Server – funciona com um único processo e compartilha “page cache” interno ao processo. (instalação padrão);
  2. SuperClassic – funciona em thread por conexão rodando com um único processo. As threads são iniciadas no processo principal e cada thread tem seu próprio “page cache”;
  3. Classic – MultiProcess, cada conexão é executada em um processo separado. Cada processo seu próprio controle “page cache”;

O modo Classic e Server possuem características paralelo ao que já tínhamos no 2.5x,  a novidade é o SuperClassic que mescla os dois outros processos, ou seja, funcionam em Thread compartilhadas e cada um mantem o seu “page cache” isolado;

Ná prática este novo modelo poderá se mostrar mais eficiente para isolamento e otimização de hardware, vamos aos teste para ver o resultado.

 

Algumas novidades do firebird 3.0 RC2

  • arquivo de configuração passa a ser   databases.conf  (antes aliases.conf);
  • quando operando como SuperServer, usa multiplos CPU / Cores;
  • a segurança passa a ser por banco de dados   (SecurityDatabase in databases.conf);
  • novo tipo de dados   BOOLEAN  aceita (True/False/Unknown);

                  CREATE TABLE TBOOL (ID INT, BVAL BOOLEAN); 
                  COMMIT;
                  INSERT INTO TBOOL VALUES (1, TRUE); 
                  INSERT INTO TBOOL VALUES (2, 2 = 4); 
                  INSERT INTO TBOOL VALUES (3, NULL = 1); 
                  COMMIT;

  • tipo IDENTITY para gerar auto-incremento internamente;
               create table objects ( 
                      id integer generated by default as identity primary key,  
                      name varchar(15) );
    
  • suporte à “Packages”;
  • suporte a “Scrollable Cursors” permitindo navegar em PSQL para frente e para traz.
  • suporte a IPV6 no servidor e no cliente;
  • validação on-line;
  • número máximo de conexões passou de 1024 para 2048;
  • toda tabela passa a ter uma coluna  RDB$RECORD_VERSION  que indica o número da transação que criou a versão do registro   (  select  RDB$RECORD_VERSION from clientes );
  • suporte a funções criadas utilizáveis em   Selects, Procedures, Trigger, Packages;

Quantas vezes precisamos fazer uma lista de notas fiscais para imprimir em um documento – ou uma lista de vencimentos…

Desejamos uma lista de notas assim:  1,2,3,4,5,10,….

O problema esta ligado  a forma como as tabelas geralmente se apresentam, assim:

NotasFiscais
-------------------------
notafiscal        valor .....
   1                x
   2                y
   ..
   10               k

No Firebird isto é simples:

Select LIST(notafiscal) from NotasFiscais where….