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.