今天发现个问题,就是SQLServer2012通过链接服务器执行SQLServer2000的存储过程的问题,就是用2012的数据库链接服务器执行2000的数据库的带参数存储过程,必须要把参数写齐,不然会出错如下:
在远程的2000版本
创建表:
USE [pubs]
GO
CREATE TABLE [dbo].[ceshi](
[id] [int] IDENTITY(1,1) NOT NULL,
[ce] [nvarchar](50) NULL,
[shi] [nvarchar](50) NULL,
[ceshi] [nvarchar](50) NULL,
CONSTRAINT [PK_ceshi] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
创建存储过程
create PROCEDURE proc_ceshi
@ce nvarchar(50)=null ,
@shi nvarchar(50)=null,
@ceshi nvarchar(50)=null
AS
BEGIN
SET NOCOUNT ON;
insert into ceshi(ce,shi,ceshi) values (@ce,@shi,@ceshi)
END
GO
在本地的2012
先安装sqlncli.msi (百度一下或者2008或者以下版本的数据库文件里面有)
创建链接服务器
USE [master]
GO
EXEC master.dbo.sp_addlinkedserver @server = N'172.16.18.11', @srvproduct=N'sqlserver', @provider=N'MSDASQL', @provstr=N'DRIVER={SQL Server Native Client 10.0};SERVER=172.16.18.11;'
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'172.16.18.11',@useself=N'False',@locallogin=NULL,@rmtuser=N'sa',@rmtpassword='password'
GO
EXEC master.dbo.sp_serveroption @server=N'172.16.18.20', @optname=N'rpc', @optvalue=N'true'
GO
EXEC master.dbo.sp_serveroption @server=N'172.16.18.20', @optname=N'rpc out', @optvalue=N'true'
GO
执行报错:
exec [172.16.18.11].pubs.dbo.proc_ceshi @ce=1,@ceshi=1 --(这个在执行里面赋值参数在本地服务器就能执行,通过链接服务器就会报错。)
--链接服务器"172.16.18.11"的 OLE DB 访问接口 "MSDASQL" 返回了消息 "至少一个变量参数的参数类型无法确定。"。
--消息 7212,级别 17,状态 1,第 1 行
解决办法:
必须遵循SQLServer数据库的原始赋值方式,定义赋值再执行。
declare @ce nvarchar(50);
declare @shi nvarchar(50);
declare @ceshi nvarchar(50);
set @ce=1;
set @ceshi=4;
exec [172.16.18.11].pubs.dbo.proc_ceshi @ce,@shi,@ceshi
或者
declare @ce nvarchar(50)=1;
declare @shi nvarchar(50)=2;
declare @ceshi nvarchar(50)=3;
exec [172.16.18.11].pubs.dbo.proc_ceshi @ce,@shi,@ceshi
意思就是不管存储过程是否允许参数有默认值,exec执行的存储过程的参数必须写完全,而且不能直接赋值在执行存储过程语句里面。
如果在执行语句里面没有写完参数并且创建时有默认值的情况下,它会按顺序填入而不会指定填入(如果类型有问题还会报错),其实这样就有点像
exec [172.16.18.11].pubs.dbo.proc_ceshi 1,2,3
它只会按参数顺序填入;
这个问题 ,链接服务器执行存储过程一般出现在跨版本的情况下,所以只有执行语句的参数写完全,对需要的参数赋值就可以了(不需要的创建时已经有默认值),这样才会识别正确的对应参数。