6

我正在尝试使用 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]
4

2 回答 2

3

虽然完全不知道这里使用的技术(除非对 SQL Server 有一些小的了解),但我会尝试回答(如果我的 jython 语法不正确,请原谅我。我试图在这里概述可能性而不是确切的代码)

我的第一种方法(在这篇文章中找到)是尝试:

cur.execute("use CSM")
cur.callproc(("CSM","dbo","dbo.DUMMY"), ["carrier1"])

这必须与sa用户始终将其dbo作为默认架构的事实有关(在此 SO 帖子中描述)

如果上述方法不起作用,我也会尝试CSM在 JDBC url 中使用数据库名称(这在将 JDBC 用于其他数据库时很常见),然后只需调用以下两个之一。

cur.callproc("DUMMY", ["carrier1"])
cur.callproc("dbo.DUMMY", ["carrier1"])

我希望这有帮助

更新:我引用了您无法查看的链接的相关部分

>> Program calls a Stored Procedure - master.dbo.xp_fixeddrives on  MS SQL Server

from com.ziclix.python.sql import zxJDBC

def getConnection():
    url = "${DBServer.Url}"
    user= "${DBServer.User}"
    password = "${DBServer.Password}"
    driver = "${DBServer.Driver}"
    con = zxJDBC.connect(url, user, password, driver)
    return con

try:
    conn = getConnection()
    print 'Connection successful'
    cur = conn.cursor()
    cur.execute("use master")
    cur.callproc(("master", "dbo", "dbo.xp_fixeddrives"))
    print cur.description
    for a in cur.fetchall():
        print a
finally:
    cur.close()
    conn.close()
    print 'Connection closed'

当您指定上述调用函数时出现的错误表明参数未正确传递。因此,请修改您的存储过程以采用默认值并尝试通过传递调用params = [None]。如果您看到调用成功,就指定数据库而言,我们一定做对了一些事情。顺便说一句:最新的文档表明您应该能够使用您的语法访问它。

于 2013-08-13T11:09:10.117 回答
3

如评论中所述,callproc仅适用于 SELECT。试试这种方法:

cur.execute("exec CSM.dbo.DUMMY @Param1='" + str(Param1) + "', @carrierId=" + str(carrierID))

请参阅此链接以获取更多详细信息。

于 2013-08-13T14:25:48.847 回答