O objetivo do Embedded SQL é facilitar a escrita e leitura de queries. Para isso, foi definida uma sintaxe para que se possa escrever a query diretamente no código AdvPL, sem a necessidade de ficar concatenando pedaços de string para compor a string final.
Mais informações sobre o desenvolvimento de queries no Protheus no link abaixo: http://tdn.totvs.com/display/framework/Desenvolvendo+queries+no+Protheus |
A utilização do Embedded SQL divide-se em:
Para compilar um código-fonte com o código escrito no formato Embedded, deve-se utilizar o produto Microsiga Protheus, com build igual ou superior a 7.00.050721P, em um ambiente com repositório para TOTVS | DBAccess (RPODB=TOP). A utilização deste recurso também depende da atualização da LIB.
cQuery:= ' SELECT SE2.E2_PREFIXO,SE2.E2_NUM ' cQuery += ' FROM '+RetSqlTable('SE2')+' SE2,'+ RetSqlTable('QEK') + ' QEK ' cQuery += ' WHERE SE2.E2_FILIAL= '+xfilial('SE2')+' AND ' cQuery += ' SE2.E2_PREFIXO <> ''+cPrefixo+'' AND ' cQuery += " SE2.D_E_L_E_T_ = ' ' " cQuery += ' ORDER BY '+RetSqlOrder('SE2') dbUseArea(.T.,'TOPCONN',TcGenQry(,,cQuery),'E2TEMP',.T.,.T.) TCSetField('E2TEMP','E2_EMISSAO','D',8,0) |
Exemplo básico - Utilizando Embedded SQL
BeginSql alias 'E2TEMP' column E2_EMISSAO as Date SELECT SE2.E2_PREFIXO, SE2.E2_NUM FROM %table:SE2% SE2,%table:QEK% QEK WHERE SE2.E2_FILIAL= %xfilial:SE2% AND SE2.E2_PREFIXO<> %exp:cPrefixo% AND SE2.%notDel% ORDER BY %Order:SE2% EndSql |
Características operacionais - Sintaxe
Há 3 opções para o %Order:
1º Opção:
%Order: % traduzido para SqlOrder(->(IndexKey())) |
2º Opção:
%Order: , % traduzido para SqlOrder(->(IndexKey())) |
3º Opção:
%Order: , % traduzido para SqlOrder(->(DBNickIndexKey())) |
Exemplo
tam_cp := GetE2ValorSize() BeginSql alias 'E2TEMP' column E2_EMISSAO as Date, E2_VALOR as Numeric(tam_cp,2) . . . EndSql |
Caso seja utilizado algum argumento inválido para especificar as colunas ou erros de sintaxe nas expressões que serão transformadas para montagem da query, a compilação do código-fonte é interrompida com a ocorrência Syntax Error, informando a linha em que a primeira ocorrência foi encontrada.
EndSQL (Error C2001 Syntax error:)
Caso a ocorrência de compilação aponte diretamente para a linha do código-fonte, em que está escrita a instrução EndSQL, verifique se existe algum espaço em branco ou tabulação, a partir do início da linha, antes da instrução EndSQL. A versão atual deste ambiente não suporta esta declaração, exigindo que a instrução EndSQL seja alinhada à esquerda do código-fonte, sem espaço ou tabulações.
• Query Argument Error: Alias [XXX] already in use.
Caso a instrução BeginSQL especifique um alias que já esteja aberto (em uso), a aplicação é abortada com ocorrência de erro fatal, informando em XXX o alias utilizado.
• Query Argument Error: Invalid Value Type [X]
Caso alguma expressão informada na query, através da tag %exp:...%, retorne um valor do tipo diferente de C (Caracter), D (Data), N (Numérico) ou L (Lógico), a aplicação é abortada com ocorrência de erro, em que o tipo do argumento inesperado é apresentando em [X].
• Type Mismach on +
Esta ocorrência, se reproduzida, informará na pilha de chamadas o número da linha do código-fonte correspondente à instrução EndSQL. Essa ocorrência ocorre caso alguma função intermediária do engine do Embedded SQL, excluíndo-se as funções especificadas na query com a sintaxe %exp:...%, retornar um conteúdo não caractere que será acrescentado na query. Esta ocorrência é mais dificil de localizar, sendo útil nestes casos a análise do arquivo temporário gerado pelo TOTVS | Development Studio, no momento da compilação.
• Help NOFUNCW - Função __EXECSQL
Caso um código-fonte Embedded SQL seja executado em um repositório que não tenha sido atualizado ou que não seja um repositório para o ambiente TOTVS | DBAccess (RPODB=TOP), a aplicação exibirá essa ocorrência, indicando que a função interna de execução da query não está presente no ambiente. Verifique se a LIB está atualizada e se o RPO, em uso, pertence a um ambiente TOTVS | DBAccess.
Dada a montagem da query, não é possível depurar o bloco do código/codeblock compreendido entre as intruções BeginSQL e EndSQL, não sendo considerados pontos de parada de depuração (BreakPoints), caso colocados neste intervalo do código. A colocação de pontos de parada deve ser realizada antes ou depois desse bloco.
Função auxiliar - GetLastQuery()
Após a abertura do cursor, no alias especificado, a função GetLastQuery() retorna um array, com 5 elementos, onde estão disponíveis as seguintes informações sobre a query executada.
[1] cAlias - Alias usado para abrir o cursor.
[2] cQuery - Query executada.
[3] aCampos - Array de campos com critério de conversão especificados.
[4] lNoParser - Caso verdadeiro (.T.), não foi utilizada a função ChangeQuery() na string original.
[5] nTimeSpend - Tempo, em segundos, utilizado para abertura do cursor.
Exemplo mais completo
AdvPL
BeginSql alias 'E2TEMP' column E2_EMISSAO as Date, E2_VALOR as Numeric(tam_cp,2) column QEK_SKLDOC As Logical SELECT SE2.E2_PREFIXO, SE2.E2_NUM, SE2.E2_FORNECE, SE2.E2_LOJA, SE2.E2_VALOR, SE2.D_E_L_E_T_ DEL1, QEK.D_E_L_E_T_ DEL2 , QEK.QEK_SKLDOC, SE2.R_E_C_N_O_ SE2RECNO FROM %table:SE2% SE2, %table:qeK% QEK WHERE SE2.E2_FILIAL= %xfilial:SE2% AND qek.%notDel% and SE2.E2_PREFIXO<> %exp:cPrefixo% AND SE2.E2_NUM<> %exp:(cAlias)->M0_CODIGO% AND SE2.E2_NUM<>45 AND SE2.E2_FORNECE=%exp:Space(Len(SE2->E2_FORNECE))% AND SE2.E2_EMISSAO<>%exp:MV_PAR06% AND SE2.E2_LOJA<>%exp:MV_PAR05% AND SE2.E2_VALOR<>%exp:MV_PAR04% AND qek.QEK_SKLDOC<>%exp:MV_PAR03% And SE2.%notDel% ORDER BY %Order:SE2,1% EndSql |
Código-fonte gerado pelo pré-compilador (PPO)
__execSql('E2TEMP',' SELECT SE2.E2_PREFIXO,SE2.E2_NUM, SE2.E2_FORNECE, SE2.E2_LOJA,SE2.E2_VALOR, SE2.D_E_L_E_T_ DEL1, QEK.D_E_L_E_T_ DEL2 , QEK.QEK_SKLDOC, SE2.R_E_C_N_O_ SE2RECNO FROM '+RetSqlName('SE2')+' SE2, '+RetSqlName('QEK')+' QEK WHERE SE2.E2_FILIAL= '' +xFilial ('SE2')+'' AND qek.D_E_L_E_T_= ' ' and SE2.E2_PREFIXO<> '+___SQLGetValue(CPREFIXO)+' AND SE2.E2_NUM<> '+___SQLGetValue((CALIAS) ->M0_CODIGO)+' AND SE2.E2_NUM<>45 AND SE2.E2_FORNECE= '+___SQLGetValue(SPACE(LEN(SE2->E2_FORNECE)))+' AND SE2.E2_EMISSAO<> '+___SQLGetValue(MV_PAR06)+' AND SE2.E2_LOJA<> '+___SQLGetValue(MV_PAR05)+' AND SE2.E2_VALOR<> '+___SQLGetValue(MV_PAR04)+' AND qek.QEK_SKLDOC<> '+___SQLGetValue(MV_PAR03)+' And SE2.D_E_L_E_T_= ' ' ORDER BY '+ SqlOrder(SE2->(IndexKey(1))),{{'E2_EMISSAO','D',8,0},{'E2_VALOR','N',tam_cp,2},{'QEK_SKLDOC','L',1,0}},.T.) |
A formação aplicada no embedded SQL segue a formatação horizontal padrão e por ser um comando, deve seguir a capitulação heterogénea:
// EmbeddedSQLQuery.prw #INCLUDE "TOTVS.CH" Function EmbeddedSQLQuery() BeginSQL Alias cAliasTrb SELECT R_E_C_N_O_ RECNOSN1 FROM %Table:SN1% WHERE N1_FILIAL = %XFilial:SN1% AND N1_CBASE >= %Exp:MV_PAR01% AND N1_CBASE <= %Exp:MV_PAR02% AND N1_ITEM >= %Exp:MV_PAR03% AND N1_ITEM <= %Exp:MV_PAR04% AND N1_GRUPO >= %Exp:MV_PAR05% AND N1_GRUPO <= %Exp:MV_PAR06% AND N1_AQUISIC >= %Exp:MV_PAR07% AND N1_AQUISIC <= %Exp:MV_PAR08% AND %Exp:cWhere% AND %NotDel% EndSQL Return |
O Embedded SQL trabalha em dois momentos, na pré-compilação e em tempo de execução. Durante esses processamentos, diversos valores da query são substituídos por uma interrogação (?), logo esse é um caractere reservado do Embedded SQL e utilizá-lo tanto na query quanto nos valores, pode levar a cenários de não conformidade.
Para situações que sua query ou seus valores de substituição presentes dentro dos percentuais possuem o caractere de interrogação, recomendamos o uso das seguintes classes:
Índice: