我正在尝试使用 zxJDBC 连接到在 SQL Server 2008 R2 (Express) 上运行的数据库并调用存储过程,将其传递给单个参数。我正在使用 jython-standalone 2.5.3,理想情况下不想安装额外的模块。
我的测试代码如下所示。
数据库名称是CSM
存储过程:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE dbo.DUMMY
-- Add the parameters for the stored procedure here
@carrierId VARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO dbo.carrier (carrierId, test)
VALUES (@carrierId, 'Success')
END
GO
Jython 脚本:
from com.ziclix.python.sql import zxJDBC
conn = None
try :
conn = zxJDBC.connect('jdbc:sqlserver://localhost\SQLEXPRESS', 'sa', 'password', 'com.microsoft.sqlserver.jdbc.SQLServerDriver')
cur = conn.cursor()
cur.callproc(('CSM','dbo','DUMMY'), ['carrier1'])
conn.commit()
except Exception, err :
print err
if conn:
conn.rollback()
finally :
if conn :
conn.close()
通过使用cur.execute()
,我已经能够验证上述是否成功连接到数据库,并且我可以对其进行查询。但是,到目前为止,我一直无法成功调用带有参数的存储过程。
此处的文档(可能已过时?)表明callproc()
可以使用字符串或元组调用以识别过程。给出的例子 -
c.callproc(("northwind", "dbo", "SalesByCategory"), ["Seafood", "1998"], maxrows=2)
当我尝试使用此方法时,我收到以下错误
Error("Could not find stored procedure 'CSM.DUMMY'. [SQLCode: 2812], [SQLState: S00062]",)
zxJDBC 似乎忽略了包含dbo
过程标识符的部分。
如果我改为callproc
使用“CSM.dbo.DUMMY”作为第一个参数调用,那么我会收到此错误
Error('An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name. [SQLCode: 1038], [SQLState: S0004]',)
在运行我的脚本时在数据库上使用探查器表明,在第二种情况下,将执行以下 SQL:
use []
go
因此,当使用单个字符串来标识过程时,似乎没有正确解析出数据库名称。
我尝试解决此问题的尝试之一是调用 callproc,如下所示:
cur.callproc(('CSM', '', 'dbo.DUMMY'), ['carrier1'])
这让我只有
Error("Procedure or function 'DUMMY' expects parameter '@carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",)
在这种情况下,我认为正在发生的事情是 zxJDBC 尝试调用系统存储过程 ( sp_proc_columns
) 以确定我要调用的存储过程所需的参数。我的猜测是,由于上述格式不正确的过程标识符,zxJDBC 没有得到有效/正确的返回,并且假定不需要任何参数。
所以基本上我对如何获得它的想法并不感到困惑
- 使用正确的数据库名称
- 使用 sp_proc_columns 正确确定所需参数
- 用正确的名称调用我的存储过程
同时。
我确实有一个解决方法,那就是使用类似的东西
cur.execute('EXEC CSM.dbo.DUMMY ?', ['carrier1'])
但是我觉得callproc()
这是正确的解决方案,并且当我调用具有大量参数的存储过程时可能会产生更清晰的代码。
如果有人能发现我正在犯的错误,或者知道这不会像我想的那样奏效,那么任何输入都将不胜感激。
谢谢
编辑
正如 i-one 所建议的,我尝试cur.execute('USE CSM')
在调用我的存储过程之前添加(也从过程调用中删除数据库名称)。不幸的是,这会产生与上述相同的对象或列缺失错误。探查器显示USE CSM
正在执行,然后USE []
似乎 callproc() 总是USE
在过程本身之前触发一条语句。
我也尝试过打开/关闭自动提交,但无济于事。
编辑 2
评论/建议解决方案后的更多信息:
- 我的连接字符串中的“SQLEXPRESS”是数据库实例名称。
- 使用双引号而不是单引号无效。
- 在连接字符串中包含数据库名称(通过此处
;databaseName=CSM;
指定)并在 callproc() 调用中省略它会导致原始错误,并触发语句。USE []
使用callproc(('CSM', 'dbo', 'dbo.DUMMY'), ['carrier1'])
给了我一些进步,但导致错误
错误(“程序或函数'DUMMY'需要参数'@carrierId',未提供。[SQLCode:201],[SQLState:S0004]”,)
我将尝试进一步调查
编辑 3
根据我可以看到 zxJDBC 触发的查询,我对我的数据库手动执行了以下操作:
use CSM
go
exec sp_sproc_columns_100 N'dbo.DUMMY',N'dbo',N'CSM',NULL,N'3'
go
这给了我一个空的结果集,这似乎可以解释为什么 zxJDBC 没有将任何参数传递给存储过程——它认为不需要。我还没有弄清楚为什么会这样。
编辑 4
要更新上述内容,空结果集是因为调用应该是
exec sp_sproc_columns_100 N'DUMMY',N'dbo',N'CSM',NULL,N'3'
不幸的是,这给我带来了完整的循环,因为我无法dbo
在 callproc() 调用中从存储过程名称中删除所有者,否则根本找不到该过程。
编辑 5
按要求定义表
CREATE TABLE [dbo].[carrier](
[carrierId] [varchar](50) NOT NULL,
[test] [varchar](50) NULL
) ON [PRIMARY]