想写一个SQL查询及执行器,现在碰到的问题是例如我用ADODataSet(或者用CoreLab的DAC系列控件)当用户输入一条SQL后,这句SQL有可能是有返回结果集的(例如用select语句),也有可能没有返回结果集的(例如用Delete或update),那么应如何使用办呢,究竟用DataSet的Open还是Execute方法呢?
如果用Open的话,对于没有结果集返回时就会报错,如果用Exectue的话,那么又不会返回结果集。
那么应如何解决这个问题?
如果用Open的话,对于没有结果集返回时就会报错,如果用Exectue的话,那么又不会返回结果集。
那么应如何解决这个问题?
解决方案 »
- 请教:如何打开一个无格式的文件并替换里面的某个字符串但并不影响文件原有格式?
- WWDBGRID问题如何才能实现这个功能,请高人指点!!!
- 问一个紧急问题 关于 CoolTrayIcon 和XPMenu
- 把数个图形文件合并成GIF文件,想幻灯片一样播放
- 用FastReport查询报表30秒钟时报"TimeOut expired"错误,求助在线等待.
- 关于菜单字体在WIN2000和WIN98下的显示问题?
- 再问一次?谁知道如何将以下Delphi的代码转成BCB的?
- 向仍然工作的朋友问好(放分)
- 高手帮忙
- 怎样象WinZip一样在Windows中加入自己的菜单项?
- 提示框不能正常显示
- 还有一个小小的问题
放置一个adoQuery,命名为:adoMyQuery,
try
adoMyQuery.Open;
except
try
adoMyQuery.ExecSQL;
except on E:Exception do
begin
adoMyQuery.Close;
showmessage('命令执行失败!原因:'
+ #13 + E.Message);
EXIT;
end;
end;
end;请结分。100分噢。
关键是SQL语句千变万化?很难讲那个一定有返回集,举个例子说,如果用户执行的储存过程的话,那根本无从判断。
我一早就是这样做了,原来也是很好的,但如果碰到的是Oracle的DDL(例如Create Table等)语句的话,就会出错。
try
FDacDS.SQL.Assign(FslContent);
FDacDS.Open;
dspContent.DataSet := FDacDS;
cdsContent.Active := true;
mgrContent.DoFieldInit;
labMsg.Caption := 'Rows:'+ IntToStr(cdsContent.RecordCount);
except
on E : Exception do
begin
try
FDacDS.Free;
FDacDS := FlexCoreLibDBUnit.CreateDataSet(BaseConf.CnnMgr.GetConnection(cmbConnection.Text));
FDacDS.SQL.Assign(FslContent);
FDacDS.Execute;
BaseConf.MyMessageBox(Handle,' 执行成功! ', MB_ICONINFORMATION + IDOK);
except
on E : Exception do
begin
BaseConf.MyMessageBox(Handle,E.Message, MB_ICONWARNING + IDOK);
exit;
end;
end;
end;
on E : Exception do
begin
BaseConf.MyMessageBox(Handle,E.Message, MB_ICONWARNING + IDOK);
exit;
end;
end;
try
open;
except
Exectue;
end;
adoquery.sql.test:='select .....'
if LowerCase(copy(sql.text,1,6))='select' then
adoquery.open
else
adoquery.execsql;
...
sqltext:='select ....';
if trim(left(sqltext,6))='select ' then
ado.open
else ado.execsql;2、不知道sql串的情况
try
ado.open;
except
ado.execsql;
end;
我不是用Delphi的新手,所以不要以为我连open与execute什么时候用也搞不清,请不要用以下或类似的方法,因为我已试过,无效:1.用判断的方法去识别语句
原因:SQL语句千变万化,很难说那个一定有返回集,举个例子说,如果用户执行的储存过程的话,那根本无从判断。2.使用类似以下方式
try
adoMyQuery.Open;
except
try
adoMyQuery.ExecSQL;
except on E:Exception do
begin
adoMyQuery.Close;
showmessage('命令执行失败!原因:'
+ #13 + E.Message);
EXIT;
end;
end;
end;
上面的方式,一般情况下可以对付,但如果碰到的是Oracle的DDL(例如Create Table等)语句的话,就会出错。其实就是因为Open语句执行完了(即执行了Create Table),但还是抛出Exception,而Execute又继续执行一次。
(Pos('INTO', UpperCase(sSQL)) = 0) and
(Pos('UPDATE', UpperCase(sSQL)) = 0) then
begin
adoMyQuery.Open;
end
else
begin
adoMyQuery.Execute;
end;
其它的就判断SELECT INSERT这些。
CSDN的Delphi论坛真的有点不如DelphiBBS,我已在DelphiBBS中找到了答案,但也谢谢各位的热心。http://www.delphibbs.com/delphibbs/DispQ.asp?LID=3888475
如果是有数据返回的,ado数据集也能捕获到数据。
确实我是觉得CSDN里面的Delphi论坛比不上DelphiBBS的,这其实也不只是我一个人是这样认为的,你自己也可以去那里看看去比较一下。但这并不代表我认为在CSDN上的同行水平会比别人差。
另外,我的BLOG在CSDN上而不在DelphiBBS上,是因为我也十分留恋CSDN。之前在它上面学到很多的知识。但这些年来,CSDN对Delphi的支持十分的少,你看看它的版面编排就知道了。这是十分让人失望的事。你再看看《程序员》杂志,它们有多少期会提及Delphi?反正你如果看《程序员》,你就会觉得Delphi简直是没落了(Perl的内容比Delphi还要多得多),而事实真的如此吗?
Borland或许真的有点没落了,但Delphi远还不至于此!!!
Exec '客户输入的SQL语句';
try
strSQL:='客户的SQL语句'
with 数据集 do
begin
Close;
SQL.Text:='exec('+QuotedStr(strSQL)+')';
ExecSQL;
end;
except
异常处理
end;
----------------
来自:levi, 时间:2008-4-24 16:57:45, ID:3888579
试试我的这个方法,肯定行。
首先用ADOConnection.execute执行命令,我试过了执行 select、Delete、存储过程都没问题。
var aaa:_Recordset;aaa:= ADOConnection1.Execute('exec Add_Assigner ''000'', ''002''');
aaa:= ADOConnection1.Execute('select * From Table1');
aaa:= ADOConnection1.Execute('Delete From Table1 Where Code=''00''');
(上面语句一次选一个就行了,我是上述三种类似都试过了,都不会出错)
if Assigned(aaa) then
if aaa.Fields.Count > 0 then
ADODataSet1.Recordset := aaa;原理:其实无论ADOQUERY还是ADOTABLE,最终都是执行adoconn.execute来执行语句或都存储过程的
execute有两种方式,
一种是不返回结果,是PROCEDURE
procedure TADOConnection.Execute(const CommandText: WideString;
var RecordsAffected: Integer; const ExecuteOptions: TExecuteOptions = [eoExecuteNoRecords]);
var
VarRecsAffected: OleVariant;
begin
CheckActive;
ConnectionObject.Execute(CommandText, VarRecsAffected,
adCmdText+ExecuteOptionsToOrd(ExecuteOptions));
RecordsAffected := VarRecsAffected;
end;一种是返回结果,是Function
function TADOConnection.Execute(const CommandText: WideString;
const CommandType: TCommandType = cmdText;
const ExecuteOptions: TExecuteOptions = []): _Recordset;
var
VarRecsAffected: OleVariant;
begin
CheckActive;
Result := ConnectionObject.Execute(CommandText, VarRecsAffected,
Integer(CommandTypeValues[CommandType])+ExecuteOptionsToOrd(ExecuteOptions));
end;如果数据集控件是用execsql的,就调用procedure execute, 相反就调用 function execute, 交叉时就会出错楼上讲的提示。 现在我们把这过程提前到先用function ADOCONN.EXECUTE()执行语句,然后自行判断有无结果返回,如有,才直接将结果赋值给ADODataSet显示,避免DELPHI默认的用ADOQuery.Open就调用funtion execute, 用EXECSQL就调用Procedure execute , 这样就可以解决楼主的问题了。
来自:flexitime, 时间:2008-4-24 23:25:10, ID:3888679 | 编辑搞了半天,原来自己是个大傻瓜~~~,幸好也学到了其它的知识(再次感谢levi)我的程序其实是用CoreLab的OraDAC,MyDac,MSDAC等组件写的,而不是用ADO来写的,但因为ADO以前用得比较多,所以也十分清楚ADODataSet.Execute是不返回结果集的,所以一直也认为其它的组件也不返回结果集的。(BDE, DBX等也确定是不返回)。
但今天回到家里试一下levi的方法,对ADO确实是有效,但对CoreLab的东西是无效的,原因是_RecordSet是AdoInt中的东西。DAC是没有的。无奈,自己再一次去查DAC的源码,结果在DBAccess.pas单元中发现procedure TCustomDADataSet.Execute;
var
ReExecute: boolean;
begin
if UsedConnection <> nil then
UsedConnection.PushOperation(clExecute);
try
if Executing then
Exit;
BeginConnection;
if Active then
Close;
repeat
ReExecute := False; BeforeExecute;
if not FNonBlocking then
StartWait;
try
if Options.AutoPrepare then
Prepare;
if IsQuery then begin
Open; //看到了,就是这里,在Exceute里居然会先判断是否查询,是的话再Open!CoreLab真是太可爱了~~
EndConnection; //Here we decrement UsedConection.FConnectCount that was incremented in InternalExecute and then
//in OpenCursor, also we make disconection in case of all data fetched during Opening (Less or equal to one fetch block)
end
else begin
// get param values from master dataset
if (FDataLink.DataSource <> nil)
and (FDataLink.DataSource.DataSet <> nil)
and (FDataLink.DataSource.DataSet.Active)
then
SetMasterParams(Params);
if FNonBlocking then
SetCursor(crSQLArrow);
FCommand.WriteParams;
InternalExecute;
if IsQuery then begin
Open;
EndConnection; //Here we decrement UsedConection.FConnectCount that was incremented in InternalExecute and then
//in OpenCursor, also we make disconection in case of all data fetched during Opening (Less or equal to one fetch block)
end;
end;
except
on E: TObject do begin
if FNonBlocking then begin
StopWait;
end;
if (E is EFailOver) and (EFailOver(E).FConnLostCause = clExecute) then begin
UsedConnection.RestoreAfterFailOver; //Restore all read transactions
ReExecute := True; //We should pass clConnectionApplyUpdates FailOver
end
else begin
EndConnection;
raise;
end;
end;
end;
until (not ReExecute);
finally
if UsedConnection <> nil then
UsedConnection.PopOperation;
end;
end;原来DAC的Execute是会返回结果集的!!!!!!晕死~~~~~