Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Diferenças entre DBC e SQL
Message
De
06/09/2005 15:51:28
Peter Wagner
Point Informática Ltda.
Limeira, Brésil
 
Information générale
Forum:
Visual FoxPro
Catégorie:
Base de données, Tables, Vues, Index et syntaxe SQL
Divers
Thread ID:
01046086
Message ID:
01047143
Vues:
8
Rodolfo,
vamos por partes....
O VFP é como Neston tem mil maneiras de fazer, o SQL Server só algumas...

Vou te passar 2 ideias que me vem a mente agora de como se pode tentar resolver o problema.

1) Vc pode criar uma função tipo Verifica_campos( ) na classe do Form ou uma classe generica e em cada formulário antes do metodo para salvar, vc pode verificar se os campos estão preenchidos conforme as regras.
(esta forma é a mais facil pois vc domina o VFP)
O problema deste caso é que o controle fica no frontend em vez de no servidor.
A vantagem é que não existe trafego na rede se a verificação falhar.

2) Outra forma de vc resolver este problema, é vc partir para Stored Procedures (SP) no SQL Server.
Neste caso em lugar de construir um string de inclusão/atualização/exclusão vc terá de criar pelo menos 3 Stored Procedures por tabela para capturar todas as possibilidades.

Neste caso vc tera de construir uma chamada a Stored Procedure no VFP, passando os parametros na mesma ordem dos campos, ou passando o nome de referencia do campo a SP do SQL.

Vc deve saber que pode criar mensagens proprias no SQL Server, desde que tenham uma numeração superior a 50.000 (veja o BOL).

Vamos supor que a sua SP de inclusão basica seja esta...
CREATE PROCEDURE  SPA_INS_Clientes
@CPF CHAR(14)
,@NOME CHAR(50)
,@ENDERECO CHAR(50) = NULL
,@OCUPACAO CHAR(50) = NULL

AS 
BEGIN TRANSACTION 

INSERT INTO Clientes(
CPF
,NOME
,ENDERECO
,OCUPACAO
)
 VALUES (@CPF
,@NOME
,@ENDERECO
,@OCUPACAO
)
IF (@@ERROR <> 0) -- Houve ERRO na inserção do registro
	BEGIN
		ROLLBACK TRANSACTION
		RAISERROR 65006 'Erro na inclusão do registro'
	END
ELSE
	BEGIN
		COMMIT TRANSACTION
	END
*****
No VFP vc tem que fazer a chamada a esta SP, se fosse via CA o codigo seria desta forma:
EXECUTE SPA_INS_CLIENTES  ?ca_Clientes.CPF,  ?ca_Clientes.NOME,  ?ca_Clientes.ENDERECO,  ?ca_Clientes.OCUPACAO
O mesmo vc teria de fazer com Update e Delete.

Vamos supor que vc queira incluir a verificação de alguma coluna...
A Stored Procedure permite que vc faça a verificação antes de 'BEGIN TRANSACTION' no código acima.
Basta vc inserir o codigo equivalente ao do VFP em T-SQL...(um SELECT na Tabela para comparar o valor do CPF do parametro com os CPF cadastrados, se já existir, apresenta mensagem de erro).
(Não vou exibir aqui por falta de tempo) Sorry ;).

Lembra acima que pode criar mensagens proprias no SQL ?
Bem em vez de retornar como no exemplo Acima o erro 65006, que é uma menssagem que eu criei no SQL vc pode simplificar e retornar a mensagem de erro normal e um código.
Vc pode fazer o Aerror( ) do VFP capturar este código e exibir uma mensagem para o seu usuário no frontend em lugar da mensagem do SQL.

Vou abordar algo relacionado ao assunto...
Eu não gosto das constraints pois elas complicam a vida do desenvolvedor.
Prefiro usar uma abordagem do seguinte tipo:
a) fazer chamada a SP no SQL passando os parametros.
b) se tiver de verificar algo, posso fazer a verificação na propria SP antes de inserir/atualizar ou fazendo chamada a um função.
c) Fazer a validação via trigger, chamando Stored Procedures. (Veja o codigo abaixo)
Mas neste caso vc não pode usar Constraints, pois estas são disparadas antes dos Triggers.

INFELISMENTE O SQL server não tem BEFORE trigger.

Segue abaixo um codigo p/ validar CPF p/ SQL Server

Na verdade, é 1 procedure e 1 trigger. O trigger chama as procedures passando CPF e CGC como parâmetros e recebe o retorno de erro que irá determinar se a transação será abortada ou não.
(adapte a ideia para o seu caso)

O trigger que estou apresentando considera que a mesma tabela tenha o campo (CPF), mas você pode adaptar esse trigger de acordo com o seu projeto!
**
* Procedure para validar CPF
**
CREATE PROCEDURE VALIDA_CPF

@valor_cpf char(11)

AS

declare @s1  numeric(20,10)
declare @s2  numeric(20,10)
declare @m1   integer
declare @m2   integer
declare @i       integer
declare @l       char(1)
declare @v      integer
declare @d1    integer
declare @d2    integer
declare @mod integer
declare @int     integer
declare @fra    numeric(20,10)
declare @msg char(50)
declare @cpf   char(11)

   select @s1 = 0
   select @s2 = 0
   select @m2 = 2
   select @cpf = @valor_cpf
   select @i = 9

   while 1 = 1

      begin
         select @l = substring(@cpf,@i,1)
         select @m1 = @m2
         select @m2 = @m2 + 1
         select @v = convert(integer,@l)
         select @s1 = @s1 + (@v * @m1)
         select @s2 = @s2 + (@v * @m2)
         select @i = @i - 1

         if @i < 1
            break
         else
            continue
         end

   select @int = @s1 / 11
   select @fra = @s1 / 11
   select @mod = round((@fra - @int) * 11,0)

   if @mod < 2
      begin
         select @d1 =0
      end
   else
      begin
         select @d1 = 11 - @mod
      end

   select @s2 = @s2 + (2 * @d1)
   select @int = @s2 / 11
   select @fra = @s2 / 11
   select @mod = round((@fra - @int) * 11,0)

   if @mod < 2
      begin
         select @d2 = 0
      end
   else
      begin
         select  @d2 = 11 - @mod
      end

   if substring(@cpf, 10, 2) <> (ltrim(str(@d1)) + ltrim(str(@d2)))
      begin
         raiserror ('digito verificador do cpf invalido', 16, -1)
         return(1)
      end
   else
      return(0)
go

**
* Trigger que dispara as procedures
**
CREATE TRIGGER TRG_CPFCGC ON dbo.Clientes
FOR INSERT,UPDATE
AS

declare @cpf char(11)
declare @cgc char(14)
declare @retorno integer

select @cpf = inserted.cpf from inserted

exec @retorno = valida_cpf @cpf

if @retorno = 1
   begin
       rollback transaction
   end

select @cgc = inserted.cgc from inserted

exec @retorno = valida_cgc @cgc

if @retorno = 1
   begin
       rollback transaction
   end
go
Veja, que desta forma o trigger funciona para 2 situações e chama a mesma SP aliviando o trabalho.

Eu pessoalmente faço uso da verificação usando uma função do tipo Verifica_campos() no VFP bem como triggers e SP no SQL server.

O motivo é o seguinte:
Se o cliente tem uma banda lerda (ADSL), procuro verificar todas as condições possiveis para minimizar o trafego na rede, pois o custo seria de ida e volta, o que pode tornar tudo lento (o gargalo geralmente em sistemas Cliente/servidor esta na rede).

Vc deve estar percebendo que se tem que escrever muito mais codigo no SQL Server que no VFP, bem o meu conselho para este caso é vc criar construtores de Stored Procedures para SQL no proprio VFP e gerar um script p/ SQL.

A maior vantagem no uso de Stored Procedures no SQL é que permite que vc tenha controle de toda a situação.

PS: Procure usar uma nomenclatura para organizar as coisas no SQL, tipo....
TB_<nome que identifica> = TABELAS
VW_<nome que identifica> = VIEWS
FN_<<nome que identifica> = FUNCTION
RL_<nome que identifica> = RULES
DF_<nome que identifica> = DEFAULTS
Procedure sempre iniciando com SPA_ 
Procedure de inserção - SPA_INS_<nome que identifica> 
Procedure de update - SPA_UPD_<nome que identifica> 
Procedure de deleteção - SPA_DEL_<nome que identifica> 
Procedure de consulta - SPA_CONS_<nome que identifica> 
Procedure SPA_<nome que identifica> 
Evite usar SP_ como inicio de uma stored procedue, pois gera sobrecarga no sistema, pois este inicio reservado ao SQL que pesquisa tabelas do sistema antes de usar a sua SP.
No lugar va de SPA_ (stored Procedure da Aplicação) ou SPU (stored Procedure do Usuário)

Espero que tenha entendido....

[ ]'s
Peter


>Obrigado pelas respostas... Já estou estudando o SQL aqui!
>
>Estou gostando de algumas coisas, mas ficando um pouco preocupado com outras...
>
>Criei uma tabela chamada Clientes (banco de dados ESTUDO do SQL Server) conforme o script abaixo:
>
>Create Table Clientes
>(
>Codigo Int Identity Constraint Clientes_Codigo_PK Primary Key,
>Cpf Char(14) Constraint Clientes_Cfp_Formato Check (Cpf Like '[0-9][0-9][0-9].[0-9][0-9][0-9].[0-9][0-9][0-9]-[0-9][0-9]') NOT NULL Constraint Clientes_CPF_Unico Unique NonClustered,
>Nome Char(50) NOT NULL,
>Endereco Char(50),
>Ocupacao Char(50) Constraint Clientes_Ocupacao_Default Default 'Consultor Independente'
>)
>
>
>Com esta tabela criada no banco de dados Estudo do SQL Server, vou tentar fazer algumas inclusões no VFP:
>
>
>nConn = SQLStringConnect("driver={sql server};server=(local);database=estudo")
>? SQLExec(nConn,[Insert Into Clientes (Cpf, Nome) Values ('000.000.000-00','Meu Primeiro Cliente')])
>? SqlDisconnect(nConn)
>
>
>Ok - Até aqui tudo perfeito... Inclui meu primeiro cliente. Vamos continuar!
>
>
>nConn = SQLStringConnect("driver={sql server};server=(local);database=estudo")
>
>? SQLExec(nConn,[Insert Into Clientes (Cpf, Nome) Values ('00.000.000-00','Meu Segundo Cliente')])
>* Erro: O Formato do Campo está fora das regras...
>? Str(SqlError[1,1])+" - "+SqlError[1,3]
>* A mensagem é essa:
>*    1526 - [Microsoft][ODBC SQL Server Driver][SQL Server]INSERT statement conflicted with COLUMN CHECK constraint 'Clientes_Cfp_Formato'. The conflict occurred in database 'Estudo', table 'Clientes', column 'Cpf'.
>
>? SQLExec(nConn,[Insert Into Clientes (Cpf, Nome) Values ('000.000.000-00','Meu Segundo Cliente')])
>* Erro: O campo CPF foi duplicado!
>* A mensagem é essa:
>*      1526 - [Microsoft][ODBC SQL Server Driver][SQL Server]Violation of UNIQUE KEY constraint 'Clientes_CPF_Unico'. Cannot insert duplicate key in object 'Clientes'.
>
>? SqlDisconnect(nConn)
>
>
>Bom, agora o bicho pegou... Eu entendi perfeitamente o que aconteceu, mas o usuário não vai entender isso de jeito nenhum. Preciso de uma mensagem amigável, algo como: Erro 1526 - Formato do CPF inválido! ou então ,Erro 1526 - CPF já cadastrado!
>
>Hoje, usando o DBF com TRIGGER de INSERT e UPDATE, faço algo do tipo:
>
>Function ChecarClientes
>   m.MsgErro = Iif(Empty(Nome),'Nome não informado'+Chr(13),'')+;
>               Iif(FormatoInvalidoCPF(Cpf),'Formato do CPF inválido'+Chr(13),'')
>   Return Empty(m.MsgErro)
>EndFunc
>
>
>Então, a variável m.MsgErro já foi declarada anteriormente e se um trigger falhar, basta pegar a mensagem nesta variável e exibir para o usuário.
>
>Tem jeito de fazer algo parecido com o SQL Server?
>
>PS: O exemplo acima foi referente ao formato do CPF, mas eu teria essa condição por todo o sistema. Além disso, quero usar os relacionamentos entre as tabelas do SQL também: ex: não excluir um produto que tenha vendas, etc etc etc - e neste caso, eu também vou precisar de uma mensagem que o usuário entenda!
>
>Abraços e obrigado pela ajuda!
Précédent
Suivant
Répondre
Fil
Voir

Click here to load this message in the networking platform