Pergunta

Estou com dois problemas...

(1) Quando eu tento escrever para um Banco de dados (SQLite) usando Delphi XE6, eu sempre fico com o Banco de dados está bloqueado mensagem de erro.Estou certo de que eu feche o banco de dados toda vez que eu acesso a ele usando o comando FDConnection1.Fechar;

(2) Como faço para INSERIR uma tabela a partir de parâmetros de entrada?Eu tenho os seguintes parâmetros de entrada

procedure TStock_Bookkeeping.Write_To_DB(const Stock_Code, Stock_Name,
Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee: string);

e tentou escrever na tabela com o seguinte comando SQL:

sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell,
         Price_Per_Share, Num_Shares, Trans_Fee) 
         VALUES (Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share,  
         Num_Shares, Trans_Fee)';

mas ele parece não funcionar...

O seguinte é o procedimento completo eu estou tendo problemas com

procedure TStock_Bookkeeping.Write_To_DB(const Stock_Code, Stock_Name,
  Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee: string);
var
  query : TFDQuery;
  sSQL: string;
begin
    query := TFDQuery.Create(nil);
  try
    ConnectToSQLite;
    query.Connection := FDConnection1;
  if Stock_Code.IsEmpty then
    ShowMessage('Stock Code Cannot Be Empty')
    else
      if Stock_Name.IsEmpty then
        ShowMessage('Stock Name Cannot Be Empty')
        else
          if Tran_Date.IsEmpty then
            ShowMessage('Transaction Date Cannot Be Empty')
            else
            begin
//              sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee) VALUES (Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee)';
              sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee) VALUES (1,2,3,4,5,6,7)';
              query.sql.Text := sSQL;
              query.ExecSQL;
              query.Open();
        end;
  finally
    query.Close;
    query.DisposeOf;
    DisconnectFromSQLite;
  end;

end;

Quaisquer sugestões serão muito apreciados.Obrigado antecipadamente.

Foi útil?

Solução

Existem duas técnicas para a execução de uma instrução SQL dinâmica.Mas vou usar mais curto, SQL, para concentrar-se na lógica:

A pura forma (usando parâmetros)

q.SQL.Text:=
  'INSERT INTO Each_Stock_Owned (Stock_Code, Stock_Name) '+
  'VALUES (:Stock_Code, :Stock_Name)';
q.Prepare; //Optional
q.ParamsByName('Stock_Code').AsString := Stock_Code;
q.ParamsByName('Stock_Name').AsString := Stock_Name;
q.ExecSQL;

O caminho sujo (edifício SQL)

q.SQL.Text:=
  'INSERT INTO Each_Stock_Owned (Stock_Code, Stock_Name) VALUES ('+
  QuotedStr(Stock_Code) + ', '+
  QuotedStr(Stock_Name) + ')';
q.ExecSQL;

As diferenças são significativas.O caminho sujo expõe a injeção de SQL problemas (como na maioria das outras línguas, quando você cria o SQL dinamicamente, mas sem parâmetros).Isso pode ser ou não ser um problema para você.Se você sabe que o procedimento só é chamado em particular pelo seu próprio código, e que aqueles procedimento valores de parâmetro só pode conter bons valores...ou se você fazer um bom parâmetro de verificação antes de criar e executar o SQL...em seguida, você está seguro.

Mas se você fizer isso com parâmetros (o puro maneira), você está automaticamente protegido contra a injeção de SQL, como a instrução SQL é validado pelo motor, sem saber os valores de parâmetro.Portanto, a instrução SQL estrutura é conhecida pelo motor e não pode ser alterada por valores reais.

Outra consideração é a frequência com que você vai executar essa instrução INSERT.A pura forma permite que você para preparar a consulta de uma VEZ, e executá-lo MUITAS VEZES com diferentes valores do parâmetro (você não deve destruir o objeto de consulta, nem alterar a propriedade SQL, e você deve chamar o método de preparação de uma vez).Se você executá-lo freqüentemente dentro de um loop, então ele pode ser mais eficiente do que a construção do SQL muitas vezes o caminho sujo.OTOH, se você só precisa inserir uma única linha, ele pode representar um pouco mais de peso.

=================

Como um aparte...CL é direito...esses valores não devem ser cadeias de caracteres.Tenha em mente que o Parâmetro de objeto tem muitas propriedades para lidar com diferentes tipos de dados:

  q.ParamsByName('somedate').AsDateTime := Date;
  q.ParamsByName('somenumeric').AsFloat := 3/4;

...e assim por diante.

Se você não usa parâmetros, então as coisas ficam difíceis.O QuoteStr função é boa para cadeias de caracteres, mas se você deseja gravar datas e moedas e outros tipos de valor diretamente em seu SQL você tem que saber o que você está fazendo.Você pode encontrar muitos problemas diferentes...localidade específicos ou configurações de formato que não são boas para a comunicação com o servidor, que pode ser o oposto do fim do mundo, ou pode simplesmente não ser capaz de ler os valores formatados de que maneira.Você pode ter que lidar com motor de formatação específica e problemas de conversão.

Se você usar os parâmetros e, em seguida, FireDAC deve cuidar de tudo isso para você ;)

Outras dicas

Para obter valores para a consulta, use os parâmetros (isto é explicado o documentação):

query.SQL.Text := 'INSERT INTO Each_Stock_Owned'+
                    '(Stock_Code, Stock_Name, Tran_Date, Buy_Sell, '+
                     'Price_Per_Share, Num_Shares, Trans_Fee) '+
                    'VALUES (:sc, :sn, :td, :bs, :pps, :ns, :tf)';
query.ParamByName('sc').AsString := Stock_Code;
query.ParamByName('sn').AsString := Stock_Name;
query.ParamByName('td').AsString := Tran_Date;
query.ParamByName('bs').AsString := Buy_Sell;
query.ParamByName('pps').AsString := Price_Per_Share;
query.ParamByName('ns').AsString := Num_Shares;
query.ParamByName('tf').AsString := Trans_Fee;
query.ExecSQL;

(E eu dúvida de que todos esses valores realmente deve ser cadeias de caracteres ...)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top