1HZV&ODULRQ%UDVLO±1~PHUR
8VDQGRDVRSo}HVGH64/DYDQoDGRGR
%URZVHGR&ODULRQ
-XOLR&pVDU3HGURVR
No Clarion 6 na janela %URZVH %R[ %HKDYLRU, uma nova guia foi
adicionada, e tenho certeza, poucos programadores já fizeram uso dela, ou
melhor, muito poucos sabem a utilidade da mesma. Basicamente o propósito
desta aba parece ser mostrar campos calculados, como por exemplo, SUM,
AVG, COUNT (Somar, Médias, Contar), mas estes campos podem mostrar
diversas informações de alto nível SQL, tais como 6WRUH 3URFHGXUHV e
/RRNXSV de tabelas não relacionadas com o uso de comandos SQL.
O objetivo deste artigo é “desmistificar” um pouco este assunto. Vamos
explicar como usar esta guia e as
propriedades SQL relacionadas
com ela tais como 35231$0(,
3523:+(5(, 352325'(5 e
3523*5283%<.
Vamos
demonstrar o uso de um
totalizador otimizado em um
Browse ABC.
Trata-se de uma idéia muito
simples:
Você configura uma lista de
campos para o engine da View e
especifica os valores para estes
campos.
Imagine uma tabela SQL de
Ordens de compra, com o prefixo
Ord, onde temos os campos:
Campo1, Campo2 e Campo3
com ações diferenciadas e
valores diferenciados para cada
um deles, como demonstra a
)LJXUD
tabela abaixo:
Campo
Sentença SQL
Significado
Ord:campo1 Sum(b.total)
Soma os itens das linhas
Ord:campo2 (Select codcli from clientes where Mostra
campos
não
codcli = a.codcli )
relacionados ao invés de
campos relacionados.
Ord:campo3 1
1
Se você tiver uma 9LHZ, com os campos acima (por ora vamos ignorar a
coluna 9DOXH), a RTL do Clarion irá criar uma sentença SELECT semelhante
a:
Select A.campo1, A.campo2, A.campo3 FROM Ordens A join, Where etc.. etc..
RTL = Run Time Library (ou livraria em tempo de execução).
Porém, com os valores especificados acima, os templates irão gerar
códigos de atribuição para as sentenças SQL (onde for especificado), para
cada campo. Explicaremos na seqüência a sintaxe deste código, mas a idéia
básica é usar a nova propriedade 35231DPH, para substituir um campo na
sentença SELECT por uma sentença SQL definida pelo usuário. Com este
1HZV&ODULRQ%UDVLO±1~PHUR
novo recurso você pode embutir sub selects e agregar funções nas sentenças
SQL que serão enviadas ao EDFNHQG pelo seu programa Clarion.
Observemos um exemplo bem simples.
Nosso “desafio” é uma coisa bastante comum. Queremos mostrar o total
de vendas por produto. Vamos usar a tabela 2UGHUBGHWDLOV, que vem com o
exemplo do Banco de Dados Northwind do MS SQL Server (não sei por que
todo mundo usa esse banco como exemplo, deve ser por preguiça mesmo!).
Quem já trabalhou com este exemplo do MS SQL Server, sabe que esta tabela
não armazena os totais em uma coluna chamada total, e, portanto eu não
posso simplesmente criar um SUM(TOTAL), o que seria muito fácil se a coluna
existisse.
Desta forma a sintaxe para obter as somas por produto é:
SELECT a.ProductID, b.ProductName, SUM(a.UnitPrice * a.Quantity a.UnitPrice * a.Quantity * a.Discount) AS Total
FROM [Order Details] a INNER JOIN
Products b ON b.ProductID = a.ProductID
GROUP BY a.ProductID, b.ProductName
A figura 1 mostra a guia Advanced SQL para os Browses do Clarion,
com diversas atribuições de campo. A razão de se atribuir o valor 1 para o
campo OrderId e ProductId é a forma como os campos são projetados pelo
Clarion quando se ligam a outras tabelas. – os campos ligados em ambas as
tabelas são projetados e o engine SQL não permite isso. Atribuindo um valor 1
para o campo, faz com que a Query seja vista como:
Select Sum etc, 1,1, b.productId, b.productname group by ...
O que resulta numa sentença ilegal para o SQL.
O exemplo da figura 1 não irá funcionar portanto. Muitas queries são
ilegais por que o campo da
chave primária é projetado na
estrutura da View.
Isto foi
resolvido no Clarion 6, quando
marcamos o checkbox 'R QRW
LQFOXGH3ULPDU\.H\LQYLHZ na
guia ([WHQG 2SWLRQV dos
Browses do Clarion 6 (hum...
então é pra isso que serve este
checkbox!), mas ainda existem
várias outras armadilhas de
sintaxe que podem comprometer
o nosso trabalho. O campo da
)LJXUD
chave primária é também
preferencialmente o campo da cláusula ORDER B, a menos que seja
sobrescrito
por
uma
sentença
352325'(5, em $GGLWLRQDO 6RUW
)LHOG.
Ainda, quando se exibe o resultado de
uma consulta do tipo total em um
browse
este
browse
deve
ser
configurado para )LOH/RDGHG, uma vez
que não é possível para o Clarion
)LJXUD
1HZV&ODULRQ%UDVLO±1~PHUR
executar um UHIUHVK, neste caso, sem atualizar todo o browse.
Antes de continuarmos, se você não possui o SQLSERVER e o Banco
de dados Northwind, você pode instalar o uma versão grátis do SQL Server
2005 Express Edition da url http://msdn.microsoft.com/vstudio/express/sql/
Depois de instalar o SQL Server 2005 Express Edition, você vai notar
que o NorthWind não faz parte do pacote, mas você poderá baixa-lo em um
download separado da url
http://www.microsoft.com/downloads/details.aspx?familyid=06616212-035646a0-8da2-eebc53a68034&displaylang=en. E pronto, agora podemos continuar
a nossa matéria.
A guia 64/ $GYDQFHG abrange as novas propriedades 35231$0(,
3523*5283%< e 3523+$9,1*, as quais requerem a sintaxe SQL
correta assim como 352364/. No início é um pouco difícil entender a
importância destas propriedades, uma vez que estamos acostumados a utilizar
352364/ para codificar a grande maioria das nossas sentenças SQL. Com o
passar do tempo vamos entendendo esta nova forma de escrever SQL dentro
da aba 64/ $GYDQFHG. Vamos analisar um exemplo do mundo real
(abstração).
8PDRSHUDomRGHVRPDWUDGLFLRQDOVHP5HVHWIURP9LHZ
No padrão do Clarion (não SQL Advanced), totalizar significa escanear
todos os registros na view. Isto é um procedimento normal para a maioria das
relações de arquivos do tipo pai-filho, mas mata a performance em browses
não filtrados e também quando mesmo existindo um filtro, este não pode ser
avaliado no servidor. Quem não conhece a lentidão dos browses com
totalizadores?
É claro que posso fazer a totalização condicional, mas infelizmente não
posso mudar o filtro condicionalmente, do tipo ordens deste mês, ou todas as
ordens, sem que tenha que mudar também a totalização. Duvido que haja
alguma maneira de condicionar a totalização para um milhão de registros em
cada conjunto de resultados, com uma boa performance. Quem já tentou
resolver isto desta forma, tenho certeza encontrou um grande problema.
O que se pode fazer é uma View semelhante à View do Browse, mas
com uma quantidade mínima de campos, usando os filtros do browse e
recuperando os totais em uma View filtrada. Para que os filtros sejam válidos
podemos ter um -RLQ com algumas tabelas relacionadas, as quais fatalmente
ocasionam falhas na implementação do -2,1 do Clarion.
Quando você projeta um -RLQ Clarion, todos os campos da tabela são
projetados para a View, a menos que você especifique os campos
individualmente com um 352-(&7FDPSR). Quando combinado com
35231$0(, usando uma função de agregação, a sentença 6(/(&7 é
inválida. Considere esta View:
View:Orders View(Orders)
Project(Ord:Total)
JOIN(Cus:K_CustomerId,Ord:CustomerId)
Project(Cus:Name)
End
End
Agora, vamos usar 35231$0(, para substituir Ord:Total por uma sentença
SUM .
1HZV&ODULRQ%UDVLO±1~PHUR
View:Orders{’Ord:Total’,Prop:Name}=’Sum(Total)’
Este código irá resultar em uma senteça SELECT semelhante a:
Select Sum(Total),b.Name from orders ...
Naturalmente esta sentença SQL não é válida pois combina uma função
de agregação com um campo não agregado (b.name), e não foi especificada a
clásula GROUP BY . Se, entretanto, eu adicionar esta sentença:
View:Orders{'
Cus:Name'
,Prop:Name}=1
Será enviada para o banco uma sentença:
Select Sum(Total),1 From Orders Join Customers on ...
O que será totalmente válido, do ponto de vista do %DFN(QG.
Abaixo temos um código de exemplo que substitui o método
5HVHW)URP9LHZ para totalizar alguns campos em uma tabela relacionada.
Também é feita uma contagem no conjunto de resultados para mostrar o
número de registros ao usuário. Filtros inválidos irão reportar os totais em toda
a tabela, e então eu posso tomar a ação adequada se o número de registros
totalizados for igual ao número total de registros da tabela.
BRWOrders.ResetFromView PROCEDURE
!Variável que guarda o status do arquivo.
LStat Ushort
!Declara uma view, alguns joins como views do browse view, mas com
!poucos campos
View:Orders View(Orders)
Project(Ord:OrderId)
Project(Ord:Total)
JOIN(Cus:K_CustomerId,Ord:CustomerId)
Project(Cus:Name)
End
End
CODE
LStat = Self.Primary.me.SaveFile() !salva o ponteiro
View:Orders{Prop:Filter}=Self.View{Prop:Filter} !Copy Filter
!ordena pelo primeiro campo para suprimir o campo da chave primária
View:Orders{Prop:Order}='
SQL(1)'
Open(View:Orders) !Abre a view
View:Orders{'
Ord:Total'
,Prop:Name}='
Sum(Total)'
View:Orders{'
Ord:OrderId'
,Prop:Name}='
Count(OrderId)'
View:Orders{'
Cus:Name'
,Prop:Name}=1
Set(View:Orders)
Next(View:Orders)
Recs = Ord:OrderId
Total = Ord:Total
Close(View:Orders)
Self.Primary.Me.RestoreFile(lStat)
Return
1HZV&ODULRQ%UDVLO±1~PHUR
Esta codificação me retorna o total imediatamente, ao invés de pendurar
a aplicação (como ocorre em processos normais com uma grande quantidade
de registros). A única coisa que não acontece é a manipulação da totalização
condicional Isto pode se resolvido, repetindo a seqüência por cada condição e
pela junção do filtro ao filtro normal.
35231DPH
PROP:Name não é uma nova propriedade, mas, no espírito do Clarion, ela é
H[WHQGLGD para as estuturas VIEW.
Considere a seguinte View:
View:Orders VIEW(Orders)
PROJECT(Ord:Total)
End
Como foi dito anteriormente com a propriedade 35231$0( podemos
mudar o valor recuperado a partir do %DFNHQG.
View:Orders{‘Ord:Total'
,PROP:NAME} = ‘Sum(Total)'
Este código irá transformar a consulta de:
Select Total From Orders
Para:
Select Sum(Total) From Orders
35231$0( pode ser usada com qualquer valor, contanto que esse valor seja
um sql válido.
3523*5283%<
Esta propriedade seta a sentença SQL pela cláusula *URXS%\, a qual permite
agrupar os dados de acordo com certas condições. Se H[WHQGHUPRV a visão
anterior para incluir o código do cliente, a consulta irá retornar um erro do tipo
“column is invalid in the select list because it is not contained in aggregate
function and there is no *5283%< clause”. Traduzindo para o “tupiniquim”. A
coluna é inválida na lista select por que ela não está contida na função de
agregação e não existe na cláusula *5283%<.
Podemos usar a propriedade 3523*URXS%\ para mostrar os registros
totalizados por cliente.
View::Orders{Prop:GROUPBY}='
Codcli'
3523+$9,1*
+DYLQJ é um elemento de filtragem aplicado à consultas, que pode ser usado
para limitar o resultado para um determinado critério. Por exemplo:
! mostra somente clientes que possuam
! ordens em valor superior a 10.000,00.
View:Orders{PROP:HAVING}='
Sum(Total)>10000'
Este é um exemplo básico, e pode não funcionar. Isto porque o SQL é
“meio burro”, e o Clarion sozinho não será capaz de “domesticá-lo” – o
programador precisa conhecer tanto de Clarion como de SQL para obter
sucesso. Quando usamos 3URS+DYLQJ temos que avaliar (evaluate) um dos
campos da lista da query, e algumas vezes temos que relembrar o prefixo
usando letras A, B, C, D, etc... baseadas na posição do campo no arquivo. (isto
pode ser alterado pela propriedade 3523$/,$6).
Recentemente adquiri o habito de colocar prefixo em todos os campos,
independente do número de tabelas na view, de modo que o código não será
quebrado se eu adicionar mais tabelas.
1HZV&ODULRQ%UDVLO±1~PHUR
64/H352325'(5
64/ é uma nova função no Clarion 6. Ela é um substituto para as sentenças
3URS6TO)LOWHU e 3URS6TO2UGHU, ambas usadas para concatenar uma
expressão regular do clarion com uma expressão SQL.
Assim, ela pode ser usada tanto em campos de filtro quanto em campos de
ordenação nas Views do Clarion. Uma das suas utilidades é a possibilidade de
fazer tabelas de ORRNXSV com (;,676 ou ,1 ou invés de ligar todas as tabelas
possívels. Por exemplo, se eu precisar enviar e-mails para todos os leitores da
News Clarion Brasil, do meu cadastro, eu uso uma query para estabelecer um
filtro em tempo de execução, para, por exemplo, filtrar somente aqueles que
tenham comprado alguma coisa relacionadas com a revista.
Mas, usamos 352325'(5 há muito tempo, não usamos? De fato, mas se
você tentar usar PROP:NAME sem uma cláusula ORDER válida, a consulta irá
falhar. A razão é que o Clarion espera por uma clausular ORDER como parte
de uma sentença de processamento da View. Se você não fornecer uma
Ordem, o Clarion irá adicionar os campos da chave primária como parte de
uma cláusula 25'(5 %<, e isto causará um erro do tipo “column is invalid”.
Uma solução é setar o $GGLWLRQDO VRUW RUGHU para o mesmo que as colunas
3523*5283%<, onde se aplicar. Uma outra solução é usar a função 64/,
como no exemplo abaixo:
View:Orders{Prop:Order}='
SQL(1)'
Com o MSSQL o número referencia a lista do select, então o servidor irá
agrupar pelo primeiro elemento da query, neste caso, SUM(Total), ordenando
pelo menor valor primeiro. Isto simplifica a codificação em certas
circunstâncias. O time de desenvolvimento da SoftVelocity considera esta a
melhor maneira para evitar a má formação de sentenças 352325'(5.
3RUTXHQmRXVDU352364/"
Depois do que foi exposto acima, vem a pergunta: “Porque usar esta
propriedade ao invés do aproach comum com 352364/ ?
Acredite ou não, é simplificação. Estas propriedades podem ser usadas
em conjunto com todas as diferentes propriedades da View, de forma que
podemos combinar 680(), $9*(). &2817(), por exemplo, com um
3523),/7(5, usando o “melhor dos dois mundos”.
Tendemos a cometer erros ( já cometi muitos) quando usamos filtros de
data em sentenças 352364/. Se eu escolher filtrar por uma data no Clarion,
usando 3523),/7(5, a 5XQ7LPH/LEUDU\ irá transformar isso para mim em
algo parecido com:
View:Orders{Prop:Filter}='
Ord:CustomerId=1 And '
|
&'
Ord:OrderDate_Date>=Date(1,1,Year(Today()))'
View:Orders{‘Ord:Total'
,Prop:Name}='
Sum(Total)'
O que os dois aproachs tem em comum, é que o filtro enviado para o
backend é uma sentença SQL Válida, mas, o filtro funcionará? Trará o
resultado esperado? O Clarion não consegue traduzir tudo, mas o engine da
View irá manipular os filtros inválidos no cliente. Isto não funcionará com as
funções de agregação da forma como estas são avaliadas no servidor.
Imagine uma situação onde um usuário cria um filtro usando 0217+(), <($5()
e 72'$<(). É uma forma inteligente de construção de filtro, mas a combinação
1HZV&ODULRQ%UDVLO±1~PHUR
resultante na aplicação cliente é a apresentação de um Total de toda a tabela,
ao invés do resultado filtrado. Podemos então, mudar o filtro para algo como:
Ord:OrderDate>=Date(Month(Today()),1,Year(Today()))
Agora a RTL irá entender corretamente.
Uma outra diferença é que quando usamos 352364/, não podemos
usar SET(view). Esta diferença é outra coisa que nos faz pensar a respeito das
técnicas aqui abordadas, dependendo sempre, das condições e convenções
que queremos implementer. O approach antigo 352364/ e as novas
propriedades aqui mostradas, compartilham o mesmo problema: pelo fato de
você estar usando constants do tipo string para os nomes dos campos,
qualquer alteração no dicionário de dados não sera carregada
automaticamente para as suas sentenças SQL.
3523:+(5(
Atualmente, 3523:+(5( é uma propriedade de arquivo, não uma
propriedade de VIEW. Ele funciona da mesma maneira que um
352364/),OWHU em uma View, só que no caso, atuando sobre um arquivo.
O uso prático disso pode ser visto em conjunção com /223 1(;7
(File). Em qualquer lugar onde você usa uma sentença &</&( na estrutura
/223, você pode usar um 3523:+(5( ; a diferença é que você terá a
avaliação da sentença no lado servidor, reduzindo consideravelmente o tráfego
de rede. Além do mais, a propriedade 3523:+(5(, pode ser configurada
no seu Dicionário de dados, como uma string de driver, mas desde que isto não
afete o engine da View. Veja e analise o código abaixo:
Clear(File)
Ord:CustomerId = Cus:CustomerId
Set(Ord:K_CustomerId,Ord:K_CustomerId)
!Pegar as ordens deste ano
Orders{Prop:Where}='
Year(OrderDate)=Year(GetDate())'
Loop Until Access:Orders.Next()
!Bloco de código obsoleto
If Year(Ord:OrderDate_Date)<>Year(Today())
Cycle
End ! final do código obsoleto.
Do ActionPerRecord
End
&RQFOXVmR
A guia 64/ $GYDQFHG dos Browses do Clarion 6 é uma das novas
implementações em Clarion que tem sido vista como uma coisa desnecessária
e complicada. Este artigo procura mostrar as vantagens de seu uso o outro
lado da resolução de problemas usando essa tecnologia. As propriedades
envolvidas disponibililizam uma interface comum para o SQL engine. Uma vez
que elas podem ser combinadas entre si, o desenvolvedor pode facilmente
expandir o código existente sem a necessidade de reescrevê-lo. Quando
usado em codificação manual, o código é fácil de ser entendido , e como
conseqüência propicia uma fácil manutenção. Não subestime as funções desta
guia. Estude-as e verá que ela pode melhorar, e muito, o desenvolvimento de
seu aplicativo.
1HZV&ODULRQ%UDVLO±1~PHUR
5HIHUrQFLDV%LEOLRJUiILFDV
-
Manual do Clarion 6
Revista News Clarion Brasil
Revista Clarion Magazine
Programando em Clarion com PostgreSQL.
Download

Usando as opç}es de SQL avançado do Browse do Clarion.