I receive an Insert Into error with this code any solution? - sql

if (conpassedt.text = '') or (regpassedt.text = '') or (regaccedt.text = '') or (regpassedt.text <> conpassedt.text) then
begin
showmessage('Please fill in all fields for input and confirm passwords match');
end else
begin
DM.qryDB.sql.clear;
DM.qrydb.sql.add('INSERT INTO tblUsers(AccountName, Password) ');
DM.qrydb.sql.add('VALUES ("'+ regaccedt.text +'", "' + THashMD5.GetHashString(regpassedt.text) + '")');
DM.qrydb.ExecSQL;
end;

Most likely, your DB requires single quotes instead of double quotes on string literals, eg:
DM.qrydb.sql.add('INSERT INTO tblUsers(AccountName, Password) ');
DM.qrydb.sql.add('VALUES (''' + regaccedt.text + ''', ''' + THashMD5.GetHashString(regpassedt.text) + ''')');
In which case, you should use QuotedStr() instead to handle quoting and escaping for you (which will better help you avoid SQL Injection attacks properly), eg:
DM.qrydb.SQL.Add('INSERT INTO tblUsers (AccountName, Password) ');
DM.qrydb.SQL.Add('VALUES (' + QuotedStr(regaccedt.text) + ', ' + QuotedStr(THashMD5.GetHashString(regpassedt.text)) + ')');
Though, you really should use a parameterized query instead, and let the DB engine work out any necessary quoting and escaping that it needs, eg:
DM.qrydb.SQL.Add('INSERT INTO tblUsers (AccountName, Password) ');
DM.qrydb.SQL.Add('VALUES (:PAccountName, :PPassword)');
DM.qrydb.ParamByName('PAccountName').AsString := regaccedt.text;
DM.qrydb.ParamByName('PPassword').AsString := THashMD5.GetHashString(regpassedt.text);

Modern versions of Delphi with Firedac have overloaded versions of various SQL methods to allow removal of a lot of the boilerplate in your question. Also as already mentioned in comments use parameters vs constructing a string.
FDQuery1.ExecSQL('INSERT INTO tblUsers(AccountName, Password) VALUES (:AccountName, :Password);',
[regaccedt.text,THashMD5.GetHashString(regpassedt.text)],
[ftWideString,ftWideString]);

Related

I keep getting "Data type mismatch in criteria expression" error in delphi

Whenever this code runs the I get the above error. The code is supposed to insert a record into a table and then delete records from another table.
for I := iMax - K to iMax do
begin
Inc(a);
with dmMenu.qryMcDonalds do
begin
SQL.Text :=
'SELECT ID, ItemID, ItemPrice, ItemCategory FROM tblCheckout WHERE ID = ' + IntToStr(I);
Open;
sItemID := Fields[1].AsString;
rItemPrice := Fields[2].AsFloat;
sItemCategory := Fields[3].AsString;
ShowMessage(IntToStr(I));
// I get the error here
SQL.Text :=
'INSERT INTO tblOrderItems (OrderItemID, OrderID, ItemID, ItemCategory, ItemPrice) VALUES ("' + sOrderID + '_' + IntToStr(a) + '"' + ', "' + sOrderID + '", "' + sItemID + '", "' + sItemCategory + '", "' + FloatToStrF(rItemPrice, ffCurrency, 10, 2) + '")';
ExecSQL;
SQL.Text := 'DELETE FROM tblCheckout WHERE ID = ' + IntToStr(I);
ExecSQL;
end; // with SQL
end; // for I
edit: I think i the problem is in the 'INSERT INTO' part. All the columns are short text except the last one, ItemPrice is a currency. I am also using Access
Please start a new project with just the following items on the main form:
A TAdoConnection configured to connect to your database;
A TAdoQuery configured to use the TAdoConnection
A TDataSource and TDBGrid configured to display the contents of the TAdoQuery.
Then, add the following code to the form
const
sSelect = 'select * from tblOrderItems';
sInsert = 'insert into tblOrderItems(OrderItemID, OrderID, ItemID, ItemCategory, ItemPrice) '#13#10
+ 'values(:OrderItemID, :OrderID, :ItemID, :ItemCategory, :ItemPrice)';
sOrderItemID = '0999';
sOrderID = '1999';
sItemID = '2999';
sItemCategory = 'Bolt';
fItemPrice = 5.99;
procedure TForm2.FormCreate(Sender: TObject);
begin
AdoQuery1.SQL.Text := sInsert;
AdoQuery1.Prepared := True;
AdoQuery1.Parameters.ParamByName('OrderItemID').Value:= sOrderItemID;
AdoQuery1.Parameters.ParamByName('OrderID').Value := sOrderID;
AdoQuery1.Parameters.ParamByName('ItemID').Value := sItemID;
AdoQuery1.Parameters.ParamByName('ItemCategory').Value := sItemCategory;
AdoQuery1.Parameters.ParamByName('ItemPrice').Value := fItemPrice;
AdoQuery1.ExecSQL;
AdoQuery1.SQL.Text := sSelect;
AdoQuery1.Open;
end;
Before compiling and running the program, review and change the values of the constants
so that they don't conflict with any rows already in your table.
The constant sInsert defines a so-called "parameterised SQL statement" Inside the Values
list, the items :OrderItemID, :OrderID, etc, are placeholders which the AdoQuery will turn into
parameters whose values you can supply at run-time, as in the block after AdoQuery1.Parameters.ParamByName(...
You should always construct SQL statements this way and not by concatenating strings
as your code attempts to do. It is far less error-prone, because it's easy to get into a
syntax muddle if you use DIY code and it also makes sure your queries are not prone
to Sql-Injection exploits, which they would be if you
give the user the opportunity to edit the SQL.
If you are using a FireDAC FDQuery, this has Params (an FD data-type) rather thn Parameters
but they work in pretty much the same way - see the Online Help.
In future, please be a bit more careful to ensure you include important details, especially things like the exact line where the error occurs - which you can check by single-stepping through your code using the debugger - and things like the exact db-access components you are using. Also try to get details right like whether a column is a "short text" type or an autonumber.
For a problem that needs to be debugged, like this one, you should also provide a complete, minimal, reproducible example, not just a snippet of code. Quite often, you will realise what the problem is while you are preparing the mre, so it helps you as well as us.
I bet the problem is in incompatible floating point format.
Use parameters to avoid it.

Update query with variable

Is it possible to update a variable with a concatenation of variables(columns of VARCHARS2)?
UPDATE ARTICLE
SET DESCRIPTION = (CPV_DESCRIPTION + '/' LEVEL1_DESCRIPTION + LEVEL2_DESCRIPTION+LEVEL3_DESCRIPTION)
WHERE ID_ARTICULO = 209;
UPDATE ARTICLE
SET DESCRIPTION = concat(CPV_DESCRIPTION,'/',LEVEL1_DESCRIPTION,' ',LEVEL2_DESCRIPTION' 'LEVEL3_DESCRIPTION)
WHERE ID_ARTICULO = 209;
Both cases it gives me an error.
As mentioned by #a_horse... concat() function only takes 2 parameters. When you specify more that 2 parameters to be concated, you need to use || operator. Also + is a logical operator in Oracle unlike its used in Java for concatenation. Try this:
UPDATE ARTICLE
SET DESCRIPTION = CPV_DESCRIPTION
|| '/'
||LEVEL1_DESCRIPTION
||' '
||LEVEL2_DESCRIPTION
||' '
||LEVEL3_DESCRIPTION
WHERE ID_ARTICULO = 209;

Record not insert in the end of access file with delphi

Im reading one Access database with ADO and copying the data to another with the same structure. My problem is that sometime, it dont insert at the end of the file.
DM1.ADOConnectionReadAccess.ConnectionString :=
'Provider=Microsoft.Jet.OLEDB.4.0;' + 'User ID=Admin;' +
'Data Source=' + Directory + 'Courbe\Courbe Actuel.mdb' + ';' +
'Mode=Share Deny None;Extended Properties="";' + 'Jet OLEDB:Engine Type=5;';
DM1.ADOConnectionReadAccess.Connected := true;
DM1.ADODataSetReadAccess.CommandText := 'select * from Courbe_Reservoir order by DateHeure';
DM1.ADODataSetReadAccess.Active := true;
So i read my database and order it by DateTime. Now, i have to do some change on the data when i copy it to the new database.
DM1.ADOConnectionCopyExcel.ConnectionString :=
'Provider=Microsoft.Jet.OLEDB.4.0;' +
'User ID=Admin;' +
'Data Source=' + Directory + 'Courbe\Part of curve.mdb' + ';' +
'Mode=Share Deny None;Extended Properties="";' +
'Jet OLEDB:Engine Type=5;';
DM1.ADOConnectionCopyExcel.Connected := true;
while not DM1.ADODataSetReadAccess.Eof do
begin
Date2 := DM1.ADODataSetReadAccess.FieldByName('DateHeure').AsDateTime;
DernierDebit := DernierDebit + DM1.ADODataSetReadAccess.FieldByName('DebitRes').AsFloat / 1000;
DM1.ADOCommandCopyExcel.CommandText :=
'INSERT INTO Courbe_Reservoir' + ' VALUES (:DateHeure1, ' +
':Niveau, ' + //niveau
':DebitRes, ' + //débit entrée
':PH, ' + //ph
':Chlore, ' + //Chlore
':Turbidite, ' + //Turbidité
':Temp, ' + //température
'0, ' + //Consommation l/min
'0, ' + //Log
':DernierDebit, ' + //Consommation journalière
'0, 0, 0, '''', '''', ''''' + ')';
DM1.ADOCommandCopyExcel.Parameters.ParamByName('DateHeure1').Value := Date1;
DM1.ADOCommandCopyExcel.Parameters.ParamByName('Niveau').Value := DM1.ADODataSetReadAccess.FieldByName('Niveau').AsFloat;
DM1.ADOCommandCopyExcel.Parameters.ParamByName('DebitRes').Value := DM1.ADODataSetReadAccess.FieldByName('DebitRes').AsFloat;
DM1.ADOCommandCopyExcel.Parameters.ParamByName('PH').Value := DM1.ADODataSetReadAccess.FieldByName('PH').AsFloat;
DM1.ADOCommandCopyExcel.Parameters.ParamByName('Chlore').Value := DM1.ADODataSetReadAccess.FieldByName('Chlore').AsFloat;
DM1.ADOCommandCopyExcel.Parameters.ParamByName('Turbidite').Value := DM1.ADODataSetReadAccess.FieldByName('Turbidite').AsFloat;
DM1.ADOCommandCopyExcel.Parameters.ParamByName('Temp').Value := DM1.ADODataSetReadAccess.FieldByName('Temp').AsFloat;
DM1.ADOCommandCopyExcel.Parameters.ParamByName('DernierDebit').Value := DernierDebit;
DM1.ADOCommandCopyExcel.Execute;
end;
When i check the new database, i got the following result in the image :
As you can see, i got a gap in time because i got a record for each minute. The missing record in the image are located elsewhere in the database.
In the end, i want to know why its not show in the same order i insert them. The bottom line is i want to export the new access database (.mdb) to an excel file using an export command but the export command seem to take the access file and copy it to excel as is, so no way to order it because the export. I dont want to go throught all the record again with a select and insert it in excel one after the other.
Right now, i got a file with almost 180 000 record and i need to split it per month, so the new database will have around 44 000 record.
Thanks for your help
Insertion location is not defined in most databases — the database engine has the liberty to store data wherever it deems most appropriate. It might choose to add records to the end of the table, but it might also choose to reuse space vacated by previously deleted records.
If you want results in a particular order, then indicate that in your selection query, typically by including an ORDER BY clause.
I believe the records should appear in the "order" you inserted them due to the nature of .mdb files (in a multi-user db this would be chaos to be anything else!). Try adding an autonumber if you don't already have one -- you can then double check after what the order the autonum's were assigned in.
I put order in quotes because order is implied by some field (eg autonum). If there is no autonum, we cannot expect the results in any particular way

Delphi 7 SQL Parameter found in Select Statement, but not Insert Statement

I am currently coding a Delphi 7 program that utilises SQL and an Access 2003 database.
The unit receives a 5 digit code from a previous unit, via a public variable (this is frmLogin.sCode). On form activation, the program will execute an SQL query to display the record from tblStudents that matches sCode. This statement uses a ParamByName line and works perfectly.
If no match is found, a message is displayed and the user is left with no option, but to click on the add user button. The user is then prompted to enter all of his details into the program, which are then passed to a class which sets out the SQL Insert Statement. A problem occurs now, however, as a message is displayed stating that Parameter Username is not found. I cannot understand why, as it is found when the Select statement is run. Please could someone help with this?
procedure TfrmProfilePage.FormActivate(Sender: TObject);
begin
//Instantiates the object.
objProfilePage := TProfilePage.Create;
sSQL := objProfilePage.SelectSQL;
ExecuteSQL(sSQl);
end;
procedure TfrmProfilePage.ExecuteSQL(sSQL : String);
begin
With dmTextbookSales do
Begin
dbgrdDisplay.DataSource := dsProfilePage;
qryProfilePage.SQL.Clear;
qryProfilePage.SQL.Add(sSQL);
qryProfilePage.Parameters.ParamByName('Username').Value := frmLogin.sCode;
qryProfilePage.Open;
If qryProfilePage.RecordCount = 0
Then
Begin
ShowMessage('Please click on the "Add Details" button to get started.');
btnChange.Enabled := False;
btnSelling.Enabled := False;
btnBuying.Enabled := False;
End;
End;
end;
procedure TfrmProfilePage.GetValues(VAR sStudentName, sStudentSurname, sCellNumber, sEmailAddress : String; VAR iCurrentGrade : Integer);
begin
ShowMessage('Fields may be left blank, but users wishing to sell textbooks should enter at least one contact field.');
sStudentName := InputBox('Name','Please enter your first name:','');
sStudentSurname := InputBox('Surame','Please enter your surname:','');
iCurrentGrade := StrToInt(InputBox('Current Grade','Please enter your current grade:',''));
sCellNumber := InputBox('Cellphone Number','Please enter your cellphone number:','');
sEmailAddress := InputBox('Email Address','Please enter your email address:','#dainferncollege.co.za');
end;
procedure TfrmProfilePage.btnAddClick(Sender: TObject);
begin
GetValues(sStudentName, sStudentSurname, sCellNumber, sEmailAddress, iCurrentGrade);
sSQL := objProfilePage.InsertSQL;
ExecuteSQL(sSQL);
btnChange.Enabled := True;
btnSelling.Enabled := True;
btnBuying.Enabled := True;
end;
The following code is obtained from the linked class, clsProfilePage:
function TProfilePage.InsertSQL: String;
begin
Result := 'INSERT INTO tblStudents (' + '[StudentID]' + ',' + '[StudentName]' + ',' + '[StudentSurname]' + ',' + '[CurrentGrade]' + ',' + '[CellNumber]' + ',' + '[EmailAddress]' + ') VALUES (' + 'Username' + ',' + QuotedStr(fStudentName) + ',' + QuotedStr(fStudentSurname) + ',' + IntToStr(fCurrentGrade) + ',' + QuotedStr(fCellNumber) + ',' + QuotedStr(fEmailAddress) + ')';
end;
function TProfilePage.SelectSQL: String;
begin
Result := 'SELECT * FROM tblStudents Where StudentID = Username';
end;
Your INSERT statement is wrong. You need to add parameters before you can set parameter values. In Delphi, you do that using : before the parameter name in your SQL statement.
In addition, Open is only used when performing a SELECT. INSERT, UPDATE, and DELETE don't return a rowset, and therefore you must use ExecSQL (the dataset method, not your function with the conflicting name) instead.
(While we're at it, never use RecordCount on a SQL dataset - it requires all rows to be retrieved in order to obtain a count, and it's not relevant when performing anything other than a SELECT anyway. Operations performed by ExecSQL should use RowsAffected instead, which tells you the number of rows that were affected by the operation.
(If you need a count of the number of rows, perform a SELECT COUNT(*) AS NumRecs FROM YourTable WHERE <some condition> instead, and access the NumRecs field using FieldByName.)
Change your function that returns the INSERT statement to something like this (the #13 in Result is a carriage return, which prevents having to manually insert spaces at the end of each line to separate SQL words):
function TProfilePage.InsertSQL: String;
begin
Result := 'INSERT INTO tblStudents ([StudentID],'#13 +
'[StudentName], [StudentSurname],'#13 +
'[CurrentGrade], [CellNumber], [EmailAddress])'#13 +
'VALUES (:Username, :StudentName,'#13 +
':StudentSurname, :CurrentGrade,'#13 +
':CellNumber, :EMailAddress)';
end;
You can then use it with ParamByName, without jumping through all of the hoops with QuotedStr and concatenation:
procedure TfrmProfilePage.AddUser;
begin
with dmTextbookSales do
begin
qryProfilePage.SQL.Text := InsertSQL;
qryProfilePage.Parameters.ParamByName('Username').Value := frmLogin.sCode;
qryProfilePage.Parameters.ParamByName('StudentName').Value := frmLogin.sUserName;
// Repeat for other parameters and values - you have to set every
// single parameter. To skip, set them to a null variant.
// Execute the INSERT statement
qryProfilePage.ExecSQL;
// See if row was inserted, and do whatever.
If qryProfilePage.RowsAffected > 0 then
ShowMessage('User added successfully');
// Perform a SELECT to populate the grid contents with the new
// rows after the update
end;
end;
I'd highly suggest you rethink this code. It's extremely convoluted, and it requires too much to accomplish a simple task (adding a new user).
If it were me, I'd use a separate query that was dedicated only to performing the INSERT operation, where you can set the SQL at design-time, and set the proper types for the parameters in the Object Inspector. Then at runtime, you simply set the parameter values and call ExecSQL on that insert query, and refresh your SELECT query to reflect the new row. It avoids all of the noise and clutter (as well as some unnecessary function calls and convoluted SQL building, opening and closing your SELECT query, etc.).
(It would also allow you to remove that horrific with statement, which leads to hard-to-find bugs and difficult to maintain code.)
You also have some bad linkages between forms, where you're referencing frmLogin (a specific form instance) from a second form. This means that you can never have more than one instance of either form in use at the same time, because you've hard-coded in that reference. I'd rethink that to use either parameters passed in when you create the form, or as properties that are set by the login form when creating the profile page form (or whatever TProfilePage is - your post doesn't say).
The best solution would be to move all of the non-UI related code into a separate unit (such as a TDataModule, which is designed to be used to work with non-visual components such as ADO queries) and remove it from the user-interface related forms anyway, which
Eliminates the coupling between forms, allowing the code to be reused.
Removes the non-visual data related components from cluttering the form and form code.
Separates the business logic (the part not related to interacting with the user) in a separate, distinct location, making it (and the code that uses it) easier to maintain.
Your insert statement is wrong. You need to replace the value for [StudentID].
'INSERT INTO tblStudents ('
+ '[StudentID]' + ','
+ '[StudentName]' + ','
+ '[StudentSurname]' + ','
+ '[CurrentGrade]' + ','
+ '[CellNumber]' + ','
+ '[EmailAddress]' + ')
VALUES ('
+ 'Username' + ',' // <-- UserName will never be replaced by a QuotedStr
// Access is looking for a column with the name
// 'UserName' which can not be found
+ QuotedStr(fStudentName) + ','
+ QuotedStr(fStudentSurname) + ','
+ IntToStr(fCurrentGrade) + ','
+ QuotedStr(fCellNumber) + ','
+ QuotedStr(fEmailAddress) + ')';

Correctly inserting literals in PL/PgSQL EXECUTE dynamic queries

The following is part of a plpgsql function. The problem is that the result of source_geom and target_geom is a character varying data type, and therefore I need to surround the both source_geom and target_geom in quotes(' '). The thing is that in plpgsql language how I don't know I can do it.
Here's what I have at the moment:
EXECUTE 'update ' || quote_ident(geom_table) ||
' SET source = ' || source_geom ||
', target = ' || target_geom ||
' WHERE ' || quote_ident(gid_cname) || ' = ' || _r.id;
The error that I am having is the following;
ERROR: syntax error at or near "C03B9E3B66052D400DDEFC2BD0F24140"
LINE 1: ...pdate track_points SET source = 0101000020E6100000C03B9E3B66...
^
QUERY: update track_points SET source = 0101000020E6100000C03B9E3B66052D400DDEFC2BD0F24140, target = 0101000020E610000075690DEF83052D40F88E75CCD4F24140 WHERE ogc_fid = 2
CONTEXT: PL/pgSQL function "create_network" line 26 at EXECUTE statement
Please any suggestions how I can solve this problem.?
Using EXECUTE ... USING with the format() function and its format specifiers will make your code much safer, simpler, easier to read and probably faster.
SQL INJECTION WARNING: If you ever accept source_geom or target_geom from the end user, your code is potentially vulnerable to SQL injection. It is important to use parameterized statements (like EXECUTE ... USING) or failing that, paranoid quoting to prevent SQL injection attacks. Even if you don't think your function takes user input you should still harden it against SQL injection, because you don't know how your app will evolve.
If you're on a newer PostgreSQL with the format function your code can be significantly simplified into:
EXECUTE format('update %I SET source = %L, target = %L WHERE %I = %L',
geom_table, source_geom, target_geom, gid_cname, _r.id);
... which handles identifier (%I) and literal (%L) quoting for you using format specifiers so you don't have to write all that awful || concatenation and quote_literal/quote_ident stuff.
Then, as per the documentation on EXECUTE ... USING you can further refine the query into:
EXECUTE format(
'update %I SET source = $1, target = $2 WHERE %I = $3',
geom_table, gid_cname
) USING source_geom, target_geom, _r.id;
which turns the query into a parameterised statement, clearly separating parameters from identifiers and reducing string processing costs for a more efficient query.
Use extra quotes:
EXECUTE 'update ' || quote_ident(geom_table) ||
' SET source = ''' || source_geom || '''
, target = ''' || target_geom || '''
WHERE ' || quote_ident(gid_cname) || ' = ' || _r.id;