I’m trying to convert some of the SQL code we use in our projects towards using parameters. Inserting works fine:
with SQLDataSet do begin
Close;
SQL.Text := 'INSERT INTO testtable (keyname, waarde) VALUES (:keyname,:waarde)';
Prepare;
for i := 1 to 10000 do begin
ParamByName('waarde').AsInteger := i;
ParamByName('keyname').AsString := 'Testa'+IntToStr(i);
ExecSql;
end;
end;
work fine and fast.
But, I can’t get it to work with select Statements.
At first the following seems to work:
with SQLDataSet do begin
SQL.Clear;
SQL.Text := 'SELECT :waarde = waarde FROM testtable WHERE keyname = :keyname';
Prepare;
for i := 1 to 10000 do begin
ParamByName('keyname').AsString := 'Testa'+IntToStr(i);
ExecSQL;
k[i] := ParamByName('waarde').AsInteger;
Close;
end;
end;
but the value of k[i] just gets filled with 0’s. Do I need to keep selecting the old fashioned way, issuing the query, opening and traversing the result set or is there a way when you have a query with only 1 row to select right into a parameter value?
Short answer: Keep doing it the way you do now. There is no reason to use parameters to fetch query results.
Longer answer:
You can use an ADOCommand (not sure what the ODBCExpess equivalent is) and execute a
SELECT INTOquery:In a similar way you can execute stored procedures.
However, using parameters is mainly done for making sure the input is valid and is treated as a certain type. It also allows databases to use better caching, because they cache the query once and see the parameters as a variable piece.
For the output (returned fields), this is useless. The query is already cached even with normal columns. So just execute the query and read its fields as you do now. You can use parameters, but they only add more complexity and limits, without any benefits. These kinds of parameters are specifically useful for reading output of stored procedures and program blocks.
In your specific case, you want to retrieve a lot of fields (maybe all?) In that case it may be better to execute a single query and loop through the results, than to execute 1000 little queries like you do now. Each query has a little overhead for initialization and such, and you save that overhead a 1000 times if you manage to query all the data you need at once.
Also, if you do that (fetching multiple records of data), there is no way to fetch those results into parameters, so that’s one of the reasons why parameters would limit you and thus another reason to use parameters only for input if you can.
Your results:
The reason you’re getting
0is because you never set the parameter value. So its value remains NULL. Because you request the value usingAsInteger, this value is converted to an integer, therefore returning0.The value returned by the query (the one field that is returned) is probably
0as well. You actually query an expressionX = Ywhere X is the value of the parameter and Y is the value of the field. Since the parameter’s value is NULL, the expression always evaluates to false (using the normal comparison operators on NULL values always returns false, no matter which operator you use or what the other value is). Since true and false are usually represented as 0/1 tiny int fields, the field value would probably return0as well. But you don’t use this value in your posted code.