i've used the parameter method but now i have a problem. i want to insert all my data inside the table. i need to insert 2 table at once. so heres my full coding. need help. why it says like that?
ADOQuery1.Close();
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('INSERT INTO STUDENT (CARD_ID,NAMA,MATRIC_ID,SUBJEK,KURSUS,FAKULTI,Seksyen,TAHUN) VALUES ');
ADOQuery1.SQL.Add('(card,nama,matric,subjek,kursus,fakulti,seksyen,tahun)');
ADOQuery1.SQL.Add('INSERT INTO subjek2 (CARD_ID, MATRIC_ID,NAMA,SUBJEK) VALUES');
ADOQuery1.SQL.Add('(card,matric,nama,subjek)');
ADOQuery1.Parameters.ParamByName('card').Value:= card1.Text;
ADOQuery1.Parameters.ParamByName('nama').Value:= Edit1.Text;
ADOQuery1.Parameters.ParamByName('matric').Value:= Edit2.Text;
ADOQuery1.Parameters.ParamByName('kursus').Value:= Edit3.Text;
ADOQuery1.Parameters.ParamByName('fakulti').Value:= Edit4.Text;
ADOQuery1.Parameters.ParamByName('seksyen').Value:= ComboBox1.Text;
ADOQuery1.Parameters.ParamByName('tahun').Value:= Edit5.Text;
ADOQuery1.Open();
There are some issues in your code.
SQL-Statement
If you want to execute more than one statement, then you have to use the statement delimiter (most times ;). You missed that in your statements.
INSERT INTO STUDENT (CARD_ID,NAMA,MATRIC_ID,SUBJEK,KURSUS,FAKULTI,Seksyen,TAHUN) VALUES
(card,nama,matric,subjek,kursus,fakulti,seksyen,tahun); -- missed ;
INSERT INTO subjek2 (CARD_ID, MATRIC_ID,NAMA,SUBJEK) VALUES
(card,matric,nama,subjek); -- optional on last statement
Parameters
Parameters in SQL-Statements must start with : otherwise they were treated as normal fields
INSERT INTO STUDENT (CARD_ID,NAMA,MATRIC_ID,SUBJEK,KURSUS,FAKULTI,Seksyen,TAHUN) VALUES
(:card,:nama,:matric,:subjek,:kursus,:fakulti,:seksyen,:tahun);
INSERT INTO subjek2 (CARD_ID, MATRIC_ID,NAMA,SUBJEK) VALUES
(:card,:matric,:nama,:subjek);
BTW: You did not provide any data to the parameter subjek in your code.
Executing Statement
Some statements return a cursor to data (SELECT) others do not (INSERT,DELETE,...).
If you are executing a statement, that did not return a cursor then you must not use Open. Instead you have to ExecSQL.
Mutiple Statements / Access / TADOQuery
You simply can not execute multiple statements using TADOQuery and Access. You have to execute the statements separately.
If you want to achieve, that all data is written or if any error occurs no data is written, then you have to start a transaction before the statements and you can commit or rollback.
Following all the advices you come to the following code (without transaction)
ADOQuery1.Close();
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('INSERT INTO STUDENT (CARD_ID,NAMA,MATRIC_ID,SUBJEK,KURSUS,FAKULTI,Seksyen,TAHUN) VALUES ');
ADOQuery1.SQL.Add('(:card,:nama,:matric,:subjek,:kursus,:fakulti,:seksyen,:tahun)');
ADOQuery1.Parameters.ParamByName('card').Value:= card1.Text;
ADOQuery1.Parameters.ParamByName('nama').Value:= Edit1.Text;
ADOQuery1.Parameters.ParamByName('matric').Value:= Edit2.Text;
ADOQuery1.Parameters.ParamByName('subjek').Value:= '????'; // I don't know what
ADOQuery1.Parameters.ParamByName('kursus').Value:= Edit3.Text;
ADOQuery1.Parameters.ParamByName('fakulti').Value:= Edit4.Text;
ADOQuery1.Parameters.ParamByName('seksyen').Value:= ComboBox1.Text;
ADOQuery1.Parameters.ParamByName('tahun').Value:= Edit5.Text;
ADOQuery1.ExecSQL;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('INSERT INTO subjek2 (CARD_ID, MATRIC_ID,NAMA,SUBJEK) VALUES');
ADOQuery1.SQL.Add('(:card,:matric,:nama,:subjek)');
ADOQuery1.Parameters.ParamByName('card').Value:= card1.Text;
ADOQuery1.Parameters.ParamByName('nama').Value:= Edit1.Text;
ADOQuery1.Parameters.ParamByName('matric').Value:= Edit2.Text;
ADOQuery1.Parameters.ParamByName('subjek').Value:= '????'; // I don't know what
ADOQuery1.ExecSQL;
You've not provided the parameters correctly (as I showed you in my previous answer). Note the colon (:) before the name of each parameter:
ADOQuery1.SQL.Add('(:card, :matric, :nama, :subjek)');
Also note (from that same previous answer) that you do not use the colon when assigning values to the paramters:
ADOQuery1.Parameters.ParamByName('card').Value := card1.Text;
And, once again, use white space in your SQL!! You save one keystroke by not putting spaces in between the comma-separated things, and make it much more difficult to read and maintain later without them. It's much easier to read (:card, :matric, :nama, :subjek) than it is to read (:card,:matric,:nama,:subjek). Start learning to do things properly now and save yourself (and others) headaches later.
Related
I have a query that is dynamically set up with a parameter.
I query for lines with a varchar field that contains values that can begin with a '!'.
But I get no match of those.
I use SQLServer as the database server.
If I take the sqlcode and run it directly in the database manager it works but not with TFDQuery.
Se the code example below:
myParameter := '!Tommy';
with qryExec do
begin
SQL.Clear ;
SQL.Add('SELECT * FROM myTable T WHERE T.Name='+quotedStr(myParameter));
active := true ;
first;
if Not Eof then
begin
Result := True;
end;
end; //with
I have no idea what's wrong here, so I would be happy if anyone could come with an explanation.
I would suggest using actual parameters which also avoids the possibility of SQL injection. There are also overloaded versions of Open that reduce the housekeeping lines.
FDQuery1.Open('SELECT * FROM myTable T WHERE T.Name= :NAME',['!Tommy'],[ftWideString]);
This works just fine:
Query = 'SELECT * from table_1 where code = :value; ';
I'm however trying to use the LIKE statement and It says that It couldn't find the parameter VALUE In this case:
Query = 'SELECT * from table_1 where code LIKE ''%:value;%''';
Param := ADOQuery1.Parameters.ParamByName('value');
Param.DataType := ftString;
Param.Value := 'bob';
I wanted to use a backslash to ignore the quotes, because It works in most languages but It looks like It doesn't work in Delphi.
Parameters automatically put the quotes around strings for you. Therefore, you cannot include such quotes in the SQL query. Because of that, you also cannot pass the % syntax with the query either.
Instead, keep your statement as the original (replacing = with LIKE), and pass the % around the actual value instead.
Query = 'SELECT * from table_1 where code LIKE :value';
Param := ADOQuery1.Parameters.ParamByName('value');
Param.DataType := ftString;
Param.Value := '%bob%';
On a side note, this code's a bit more elegant...
ADOQuery1.Parameters.ParamValues['value']:= '%bob%';
No need to tell it it's a string. It will detect that automagically.
"No need to tell it it's a string (the Param.DataType) . It will detect that automagically."
In general it is true.
Actually it depends of some TConnection properties, such as .ParamCreate,.ResourceOptions.AssignedValue.rvParamCreate, .ResourceOptions.AssignedValue.rvDefaultParamType=false,and defaultParamDataType . If those properties were not changed then
It will detect that automagically
So in some cases that would be explicit.
pL/SQL PROCEDURE
This is the code for a procedure that takes the term,lineno,component name,student id,score as input and processes the student score.
The procedure should add the score into the scores table if there are no exceptions.
CODE
CREATE OR REPLACE PROCEDURE score_details
(aterm IN scores.Term%type,
alineno IN scores.Lineno%type,
acompname IN scores.Compname%type,
asid IN scores.sid%type,
apoints IN scores.points%type)
AS sterm scores.Term%type;
slineno scores.Lineno%type;
scompname scores.compname%type;
ssid scores.sid%type;
spoints scores.points%type;
BEGIN
SELECT term,lineno,compname,sid,points
INTO sterm,slineno,scompname,ssid,spoints
FROM scores
WHERE aterm=term AND alineno=Lineno AND acompname=compname AND asid=sid AND apoints=points;
EXCEPTION
when no_data_found THEN
dbms_output.put_line('Invalid details');
ANONYMOUS BLOCK
The below is the code for anonymous block to test the above procedure.
I'm not able to get the correct result.Please help me with the code.
ACCEPT prompt 'pterm','plineno','pcompname','psid','ppoints'
DECLARE pterm scores.Term%type;
plineno scores.Lineno%type;
pcompname scores.Compname%type;
psid scores.sid%type;
ppoints scores.points%type;
BEGIN
score_details(pterm,plineno,pcompname,psid,ppoints);
END
I'm going to assume that you've intentionally missed out most of the body of your stored procedure, as it fetches some values out of a table into some local variables and then does nothing with these values.
I'm guessing that you're wondering why the values you entered in the ACCEPT line didn't make it into the stored procedure call.
ACCEPT is a SQL*Plus statement that you can use to set substitution variables. The following example creates a substitution variable named colour and displays the result. The line Yellow was typed in by me:
SQL> ACCEPT &colour
Yellow
SQL> PROMPT Your favourite colour is &colour
Your favourite colour is Yellow
You can also provide a prompt to the user to clarify what you're asking for:
SQL> ACCEPT colour PROMPT 'Enter a colour > '
Enter a colour > Yellow
and you can also use substitution variables in SQL:
SQL> select '&colour' from dual;
old 1: select '&colour' from dual
new 1: select 'Yellow' from dual
'YELLO
------
Yellow
It seems there's two things not quite right with your PL/SQL block at the moment:
Your ACCEPT statement isn't working. You haven't quite got the order of the parts of it right (if used, PROMPT must come after the variable name). Also, I don't think you can set more than one substitution variable in a single ACCEPT.
You're not using the substitution variables that contain the values entered.
I'd therefore imagine that you'd want the call to your PL/SQL block to look a bit more like the following:
ACCEPT pterm PROMPT 'Enter a term > '
ACCEPT plineno PROMPT 'Enter a line number > '
-- and similarly for the others.
DECLARE
pterm scores.Term%type := '&pterm';
plineno scores.Lineno%type := '&plineno';
pcompname scores.Compname%type := '&pcompname';
psid scores.sid%type := '&psid';
ppoints scores.points%type := '&ppoints';
BEGIN
score_details(pterm,plineno,pcompname,psid,ppoints);
END;
I am using (in a Delphi win32 application) OLE to perform search and replace in Word Documents.
THe user prepares a file with some textual tags enclosing them in "{" and "}" and saves the file.
Something like
Dear {NAME},
I want to tell you {WHAT_I_DID_LAST_WEEK}
Of course NAME and WHAT_I_DID_LAST_WEEK are DB fields that can be longer than 255.
So now by using Search and replace with OLE i get a STRING PARAMETER TOO LONG error (it seems 255 is the longest string usable there).
Is there an easy way to get rid of the problem?
Some home made solutons I thought of are:
1) truncate to 255 (good one ;) ) may be appending "..." at the end
2) for every "tag" that requires a replace of more than 255 chars I could first insert more tags like {WHAT_I_DID_LAST_WEEK_1}{WHAT_I_DID_LAST_WEEK_2}{WHAT_I_DID_LAST_WEEK_N} and then replace 255 chars at a time
(1) is a quick solution, at least user doesn't recieve the error, but of course it is not very good
(2) would probably work but it is a workaround, I would prefer another solution.
May be another solution is not use OLE Serach&Replace but use another function.
we use AWordApp.Selection.TypeText(strValue) and loop for replacing tags that have value string longer then 255 chars ...
var
AWordApp: OLEVariant;
...
AWordApp := CreateOleObject('Word.Application');
...
if (Length(strValue) > 255) then
begin
bFound := AWordApp.Selection.Find.Execute(params...);
while bFound do
begin
AWordApp.Selection.TypeText(strValue);
bFound := AWordApp.Selection.Find.Execute(params...);
end;
end;
regards
I am having a problem getting a list of fields from a query defined at run time by the users of my program. I let my users enter a SQL query into a memo control and then I want to let them go through the fields that will return and do such things as format the output, sum column values and so forth. So, I have to get the column names so they have a place to enter the additional information.
I would do fine if there were no parameters, but I also have to let them define filter parameters for the query. So, if I want to set the parameters to null, I have to know what the parameter's datatype is.
I am using Delphi 2006. I connect to a Firebird 2.1 database using the DBExpress component TSQLConnection and TSQLQuery. Previously, I was successful using:
for i := 0 to Qry.Params.Count - 1 do Qry.Params[i].value := varNull;
I discovered I had a problem when I tried to use a date parameter. It was just a coincidence that all my parameters up until then had been integers (record IDs). It turns out that varNull is just an enumerated constant with a value of 1 so I was getting acceptable results (no records) was working okay.
I only need a list of the fields. Maybe I should just parse the SELECT clause of the SQL statement. I thought setting Qry.Prepared to True would get me a list of the fields but no such luck. It wants values for the parameters.
If you have an idea, I would sure like to hear it. Thanks for any help.
Replied again 'coz I'm interested. My methods works (with my queries) because they have been pre-defined with the params' datatypes preset to the correct type:)
I'm not sure how you are expecting the query to know or derive the datatype of the param given that you are not even selecting the field that it operates against.
So I think your query setup and user input method will need more attention. I've just looked up how I did this a while ago. I do not use a parameterised query - I just get the "parameter values" from the user and put them directly into the SQL. So your sql would then read:
SELECT s.hEmployee, e.sLastName
FROM PR_Paystub s
INNER JOIN PR_Employee e ON e.hKey = s.hEmployee
WHERE s.dtPaydate > '01/01/2008'
therefore no parameter type knowledge is necessary. Does not stop your users entering garbage but that goes back to input control :)
Although a slightly different dataset type this is what I use with TClientDataset simple and effective :)
for i := 0 to FilterDataSet.Params.Count -1 do
begin
Case FilterDataSet.Params.Items[i].Datatype of
ftString:
ftSmallint, ftInteger, ftWord:
ftFloat, ftCurrency, ftBCD:
ftDate:
ftTime:
ftDateTime:
.
.
.
end;
end;
can you not do something similar with the query?
You guys are making this way too hard:
for i := 0 to Qry.Params.Count - 1 do begin
Qry.Params[i].Clear;
Qry.Params[i].Bound := True;
end;
I'm not sure what version of Delphi you are using. In the Delphi 2006 help under Variant Types, it says:
Special conversion rules apply to the
Borland.Delphi.System.TDateTime type
declared in the System unit. When a
Borland.Delphi.System.TDateTime is
converted to any other type, it
treated as a normal Double. When an
integer, real, or Boolean is converted
to a Borland.Delphi.System.TDateTime,
it is first converted to a Double,
then read as a date-time value. When a
string is converted to a
Borland.Delphi.System.TDateTime, it is
interpreted as a date-time value using
the regional settings. When an
Unassigned value is converted to
Borland.Delphi.System.TDateTime, it is
treated like the real or integer value
0. Converting a Null value to Borland.Delphi.System.TDateTime raises
an exception.
The last sentence seems important to me. I would read that as varNull cannot be converted to a TDateTime to put into the field, and hence you get the exception that you're experiencing.
It also implies that this is the only special case.
Couldn't you do something like:
for i := 0 to Qry.Params.Count - 1 do
begin
if VarType(Qry.Params[i].value) and varTypeMask = varDate then
begin
Qry.Params[i].value := Now; //or whatever you choose as your default
end
else
begin
Qry.Params[i].value := varNull;
end;
end;
What I ended up doing was this:
sNull := 'NULL';
Qry.SQL.Add(sSQL);
for i := 0 to Qry.Params.Count - 1 do begin
sParamName := Qry.Params[i].Name;
sSQL := SearchAndReplace (sSQL, ':' + sParamName, sNull, DELIMITERS);
end;
I had to write SearchAndReplace but that was easy. Delimiters are just the characters that signal the end of a word.
TmpQuery.ParamByName('MyDateTimeParam').DataType := ftDate;
TmpQuery.ParamByName('MyDateTimeParam').Clear;
TmpQuery.ParamByName('MyDateTimeParam').Bound := True;