在Delphi中,如何实现用控件执行SQL脚本更新存储过程?(200分)

X

xlzps

Unregistered / Unconfirmed
GUEST, unregistred user!
我的更新存储过程的SQL脚本(该脚本可能包括了多个存储过程的更新)是从SQL Server 中
导出的,想用Delphi控件执行SQL脚本,达到更新存储过程的目的,现发现有两个问题:
1、SQL脚本中的GO语言,Delphi不支持,运行出错(这个可以解决)。
2、因为SQL脚本是先将存储过程删除,再建立的,即CREATE PROCEDURE前面肯定还有别的语
句,而Delphi的提示是“CREATE PROCEDURE在查询中必须是第一条语句”,一直解决不了!
请问有好的解决办法吗?
 
难道真的只能找到一个GO,就取出其前面的SQL语言执行后,再往下找直到最后?[?]
 
我是用ADO连接数据库的,对于执行SQl脚本有两个心得:
1、用ADOQuery1.open,一次只能执行一条SQL语句。若有多条语句的脚本要逐条分别执行。
若你是这样执行,你的第二点在Delphi中是很好解决的。
2、用ShellExec()调用isqlw。你的问题也应该能解决的。
 
ShellExec()调用isqlw?具体怎么使用,望指点!它需要引用到什么单元?[?]
 
我只用过winexec,但,如果程序运行的机器没有安装SQL Server客户端的话,能激活服务
器的isqlw.exe吗?
 
噢,是ShellExecute吧?
 
我也觉得直接用ShellExecute把你的SQL传给ISQLW.EXE来得最简单
如果客户端没有安装的话,你就写个C/S程序,在客户端把SQL传到你的服务程序
服务程序再调用服务器上的ISQLW.EXE来执行。
用法: ISQLW.EXE
[-S <[server]>]
[-d <database>]
[-E] 受信任连接
[-U <[login id]>]
[-P <[password]>]
[-f <file list to load>]
[-i <input filename>
-o <output filename>]
[-1] 单个实例模式
[-T <template directory>]
[-D <script directory>]
[-C <configuration file>]
[-F <U | A | O>] 文件格式 (Unicode | ANSI | OEM)
 
如果你要更新存储过程只需要要SQL语句中:
CREATE OR REPLACE PROCEDURE ...
就行了,而不用先执行一句DROP PROCEDURE再来CREATE PROCEDURE,这不就变成一句了吗?
在SQL Server下不行?……那我就又找到一项Oracle比SQL Server好用的地方了,这样的话,
你就分两次来执行SQL语句嘛。
 
刚才看了一个ISQLW的帮助,发现这东东真好用,感谢xianjun和子弹,我很有收获。

下面是摘自它的帮助:

本例连接到 MyServer(pubs 数据库),并执行 input_file 中的 SQL 语句,执行结果存储在 output_file 中。
isqlw -S MyServer -d pubs -U sa -P -i input_file -o output_file


 
我怎么只是把*.sql文件装载进来了,而且查询分析器显示出来了,它不运行,下面代码有什么问题:

ShellExecute(Application.Handle, 'open', 'C:/Program Files/Microsoft SQL Server/80/Tools/Binn/isqlw.exe',
'isqlw /U sa /P /S lzx /d chss /q /f d:/CreateSp.sql', nil, SW_HIDE);

isqlw和/q有无都一样
 
你的参数出错了,应该是这样:
ShellExecute(Application.Handle, 'open', 'C:/Program Files/Microsoft SQL Server/80/Tools/Binn/isqlw.exe',
' /U sa /P /S lzx /d chss /q /i d:/CreateSp.sql /o d:/R.txt', nil, SW_HIDE);
注意/i与/o是要成对出现,另不是用/f。
 
我好象还发现个问题,就是ADO的一个控件好象不支持标签,而TDataBase控件可以,象下面的代码(只是试验用的):
if 1 < 2
goto tt
commit tran
tt:
return

在ADO下运行出错,而TDataBase里可以通过!

xianjun
谢谢,按你的写法可以解决!
我用的WinExec(PChar('isqlw -Usa -P -Slzx -dchss -i"d:/CreateSp.sql" -o"d:/eee.txt" -b'), SW_Hide);
也解决了,现在还有个问题,就是对错误的监测,看帮助说返回值小于31(32),就说明出错了,但好象不太正确,
许多情况下不管执行成功与否,winexec返回值都是33。
另外,有没有可能判断isqlw执行出错否(可能得到它的错误Id吗?),我只能想到去查找输出的的文件内容,找到
“服务器: 消息 ” ,说明执行出错了,有更好的办法吗?
 
i := WinExec(PChar('isqlw -Usa -P -Slzx -dchss -i"d:/CreateSp.sql" -o"d:/eee.txt" '), SW_Hide);
if i > 31 then
begin
if FindStr('d:/eee.txt', '服务器: 消息 ') then
showmessage('Sql执行出错!');
(FindStr是我自己写的查找字符的函数)
我想通过这种方式判断sql是否执行成功,但有个问题,WinExec执行输出的eee.txt文件总是滞后,如果一开始
没这个文件,在FindStr执行时它还没有被创建,如果有,内容也还是上次的,没有刷新,怎么解决这个问题?
winexec到底是时候产生输出文件的?

如果winexec后要中止isqlw程序又该怎么实现,用CreateProcess代替它行吗?

对API不熟悉,真是烦人,望大家能帮忙!
 
你可以等它执行完成后再调用你的FindStr
function CreateProcessAndWait(const AppPath, AppParams: String;
Visibility: word): DWord;
var
SI: TStartupInfo;
PI: TProcessInformation;
Proc: THandle;
begin
FillChar(SI, SizeOf(SI), 0);
SI.cb := SizeOf(SI);
SI.wShowWindow := Visibility;
if not CreateProcess(PChar(AppPath), PChar(AppParams), Nil, Nil, False,
Normal_Priority_Class, Nil, Nil, SI, PI) then
raise EExecuteError.CreateFmt('Failed to execute program. Error Code %d',
[GetLastError]);
Proc := PI.hProcess;
CloseHandle(PI.hThread);
if WaitForSingleObject(Proc, Infinite) <> Wait_Failed then
GetExitCodeProcess(Proc, Result);
CloseHandle(Proc);
end;
命令行执行完成后ISQLW不退出吗? 如果不退出可能给它发一个WM_CLOSE消息
或者直接用TerminateProcess(PI.hProcess)强制退出
 
xianjun
太谢谢了,你的方法我试了可行!
还有个小问题,就是CreateProcessCreateProcess(PChar(AppPath), PChar(AppParams), Nil, Nil, False,
Normal_Priority_Class, Nil, Nil, SI, PI);
因为它的第一个参数要求是执行文件的绝对路径,这样要得去查找isqlw.exe在哪,挺麻烦的,
我想给它传nil,而在第二个参数中包含它,比如这样使用:
CreateProcess(nil, PChar('isqlw -Slzx -dchss -Usa -P -i"d:/CreateSp.sql" -o"d:/eee.txt"'),
nil, nil, False, Normal_Priority_Class, nil, nil, SI, PI)
想通过这种方法来避免查找isqlw路径,在本机上运行能通过。
但确定不了这样保险不(在保证运行程序的机器安装了isqlw的前提下),望指点!
 
另外,是不是CreateProcess执行成功,就说明isqlw肯定执行过?我把该函数改了一下:
function CreateProcessAndWait(const AppParams: String; Visibility: word;
var d: DWord): Boolean;
var
SI: TStartupInfo;
PI: TProcessInformation;
Proc: THandle;
begin
FillChar(SI, SizeOf(SI), 0);
SI.cb := SizeOf(SI);
SI.wShowWindow := Visibility;
result := true;
if not CreateProcess(nil, PChar(AppParams), Nil, Nil, False,
Normal_Priority_Class, Nil, Nil, SI, PI) then
begin
result := false;
raise Exception.CreateFmt('Failed to execute program. Error Code %d',
[GetLastError]);
end;
Proc := PI.hProcess;
CloseHandle(PI.hThread);
if WaitForSingleObject(Proc, Infinite) <> Wait_Failed then
GetExitCodeProcess(Proc, d);
CloseHandle(Proc);
end;
调用代码:
if CreateProcessAndWait('isqlw -Slzx -dchss_lzx -Usa -P -i"d:/CreateuSp.sql" -o"d:/eee.txt"',SW_HIDE, d);
begin
if FindStr('d:/eee.txt', '服务器: 消息') then
showmessage('sql执行出错!');
end;

上面的代码可行吗?我只在本机调试通过了。
 
在保证运行程序的机器安装了isqlw的前提下,这样执行应该是没有问题的
有问题的话
raise Exception.CreateFmt('Failed to execute program. Error Code %d', [GetLastError]);
也会告诉你出错了。

代码应该没什么问题,但是你可以看看那d有什么作用,它是isqlw执行后的返回值
 
谢谢大家的帮忙!

特别感谢xianjun的热心帮忙!!!
 
顶部