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]',)
スクリプトの実行中にデータベースでプロファイラーを使用すると、2 番目のケースで次の SQL が実行されることがわかります。
use []
go
そのため、単一の文字列を使用してプロシージャを識別すると、データベース名が正しく解析されないように見えます。
これを修正するための私の試行錯誤の試みの 1 つは、次のように 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'])
すると、ある程度の進歩が得られますが、エラーが発生します
Error("プロシージャまたは関数 '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]