Reputation: 53
I have a table containing the field 'cost', when I try to extract its value from the table I get an error saying the field was not found.
function TSQLs.Get(value,room,hotel: string): string;
begin
with Databasehub.DataModule1 do
begin
ADOQuery1.SQL.Clear;
ADOTable1.TableName:='TblRoom';
ADOQuery1.SQL.Add('SELECT "'+value+'" FROM TblRoom WHERE RoomType="' + Room + '" AND HotelName
="'+Hotel+'"');
DataSource1.DataSet:=ADOQuery1;
ADOQuery1.Open;
if (ADOQuery1.RecordCount = 1) then
begin
Result := ADOQuery1.FieldByName(value).AsString;
end;
end;
end;
Upvotes: 1
Views: 1155
Reputation: 596497
In an SQL statement, don't surround field names in double-quotes. If a field name has spaces (or other special characters, or reserved names), use square brackets instead. And since your field name is being provided by an input string
, make sure to sanitize it before using it to avoid any SQL Injection attacks.
Also, you should be using single-quotes instead of double-quotes around string literals that are used in SQL statements:
if Pos(';', value) > 0 or Pos(',', value) > 0 then raise ...;
ADOQuery1.SQL.Text := 'SELECT [' + value + '] FROM TblRoom WHERE RoomType=' + QuotedStr(Room) + ' AND HotelName = ' + QuotedStr(Hotel);
ADOQuery1.Open;
...
A safer option to using literals is to use parameters instead (like @whosrdaddy's answer demonstrates), except that field names in a SELECT
clause can't be parameterized, so that portion of the SQL will still have to use string concatenation (after sanitizing the string):
if Pos(';', value) > 0 or Pos(',', value) > 0 then raise ...;
ADOQuery1.ParamCheck := True;
ADOQuery1.SQL.Text := 'SELECT [' + value + '] FROM TblRoom WHERE RoomType=:Room AND HotelName=:Hotel';
ADOQuery1.Parameters.ParamByName('Room').Value := room;
ADOQuery1.Parameters.ParamByName('Hotel').Value := hotel;
ADOQuery1.Open;
...
Upvotes: 1
Reputation: 11860
First of all treat the values in your program as the type in the database. Cost should be defined as a currency type in your Access DB, Delphi has a currency type too, use it as long as you can and only at presentation time, use conversion to text (or use a control that can handle the native type). Also make sure to always use parameters in your queries, or else you are vulnerable to SQL injection, as a bonus it makes your queries more readable and avoids problems like quotes in names etc...
Here is an example of a parametrized query and how to create a query on the fly
function TSQLs.GetCost(const Room : string; const Hotel: string): Currency;
var
Qry : TADOQuery;
begin
Qry := TADOQuery.Create(nil);
try
Qry.Connection := Databasehub.DataModule1.AdoConnection; // assign your TADOconnection here
Qry.ParamCheck := True; // parse parameters
Qry.SQL.Text :='SELECT Cost FROM TblRoom WHERE RoomType=:Room AND HotelName=:Hotel';
Qry.Parameters.ParamByName('Room').Value := Room;
Qry.Parameters.ParamByName('Room').DataType := ftString;
Qry.Parameters.ParamByName('Hotel').Value := Hotel;
Qry.Parameters.ParamByName('Hotel').DataType := ftString;
Qry.Active := True; // Qry.Open is also fine here
if not Qry.EOF then // don't rely on recordcount here as it could be 0 when using dynamic cursors for example
Result := Qry.FieldByName('Cost').AsCurrency;
finally
Qry.Free;
end;
end;
Upvotes: 1