Вопрос

Я сталкиваюсь с двумя проблемами ...

(1) Когда я пытаюсь написать в базу данных (SQLite) с помощью Delphi XE6, я всегда получающую базу данных заблокирован сообщение об ошибке.Я уверен, что я закрываю базу данных каждый раз, когда я получаю доступ к нему, используя команду Fdconnection1.close;

(2) Как я могу вставить в стол из входящих параметров? У меня есть следующие входящие параметры

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

и попытался написать в таблицу со следующей командой 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)';
.

Но это не работает ...

Ниже приведена полная процедура, у меня проблемы с

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;
.

Любые подсказки будут очень оценены.Заранее спасибо.

Это было полезно?

Решение

Есть два метода для выполнения динамического оператора SQL. Но я буду использовать более короткий SQL, чтобы сосредоточиться на логике:

Чистый способ (используя параметры)

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;
.

грязный путь (здание SQL)

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

Различия значительны. Грязный путь выставляет вас к проблемам впрыска SQL (как на большинстве других языков, когда вы создаете SQL Dinamically, но без параметров). Это может быть или не быть проблемой для вас. Если вы знаете, что процедура называется только в частном порядке только по собственному коду, и что эти значения параметров процедуры могут содержать только хорошие значения ... или если вы выполняете хорошую проверку параметра перед созданием и выполнением вашего SQL ... Тогда вы в безопасности ,

Но если вы сделаете это с параметрами (чистый путь), вы автоматически защищаетесь от инъекции SQL, поскольку оператор SQL проверяется двигателем, не зная значения параметров. Таким образом, структура оператора SQL известна с помощью двигателя и не может быть изменена по фактическим значениям.

Другое рассмотрение - это часто вы выполните это оператор вставки. Чистый способ позволяет вам приготовить запрос один раз и выполнить его много раз с различными значениями параметров (вы не должны уничтожать объект запроса, а также не изменить свойство SQL, и вы должны вызвать метод подготовки один раз). Если вы запускаете его часто в цикле, то это может быть более эффективно, чем наращивание SQL много раз. OTOH Если вам просто нужно вставить один разрядной строки, он может представлять немного более накладки.

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

как в сторону ... CL правильно ... эти значения не должны быть строками. Имейте в виду, что объект параметра имеет много свойств для обработки разных типов данных:

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

... и так далее.

Если вы не используете параметры, то все становится сложно. Функция Quatts хороша для строк, но если вы хотите сжигать даты и валюты и другие типы значений напрямую в вашем SQL, вы должны знать, что вы делаете. Вы можете столкнуться с множеством различных проблем ... Настройки специфических или формата локали или формата, которые не являются хорошими для крушения с вашим сервером, что может быть на противоположном конце света или, возможно, просто не сможет читать значения, отформатированные таким образом. Возможно, вам придется обрабатывать проблемы с конкретным форматированием и преобразованием двигателя.

Если вы используете параметры, то FireDAC должен заботиться обо всем этом для вас;)

Другие советы

Чтобы получить значения в запрос, используйте параметры (это объясняется Документация ):

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;
.

(и я сомневаюсь, что все эти ценности действительно должны быть строками ...)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top